home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / terms / kermit / b / ckmfio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-30  |  76.1 KB  |  2,717 lines

  1. /*
  2.   Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  3.   York.  Permission is granted to any individual or institution to use this
  4.   software as long as it is not sold for profit.  This copyright notice must be
  5.   retained.  This software may not be included in commercial products without
  6.   written permission of Columbia University.
  7. */
  8. /*
  9.   Many changes since those below by many people, 1988-1992:
  10.   Matthias Aebi, Paul Placeway, Rick Watson, Frank da Cruz, ...
  11. */
  12. /* Version 0.9(37) - Paul Placeway at Ohio State, Jan 1988 */
  13. /*  reformatted all of the code so that it would be 79 or fewer colums */
  14. /* Version 0.8(35) - Jim Noble at Planning Research Corporation, June 1987. */
  15. /* Ported to Megamax native Macintosh C compiler. */
  16. /* Original work done by Bill Catchings and Bill Schilit at Columbia Univ */
  17. /*  using the SUMACC cross compiler, 1984, adapted from UNIX ckufio.c... */
  18. /* Edit by Bill on Thu May 30, 00:18 */
  19. /* Do error handling, neaten up comments, and some code. */
  20. /* Edit by Bill on Wed May 15, 16:09 */
  21. /* Make zrtol call common sfprtol, .RSRC overrides default settings */
  22. /* ckmfio.c, Mon Apr 29 17:48, Edit by Bill*2 */
  23. /* Put null in translated name to tie it off. */
  24. /* Make author text of new file to ???? instead of random string */
  25. /* Do flushvol after closing a file */
  26. /* Bill C., Apr 24 */
  27. /* Change zchin to allow sending of files with high order bits on */
  28. /* Bill C., Apr 22 */
  29. /* Add error handling (informing) for more cases, e.g. can't delete */
  30. /* Bill C., Apr 22 */
  31. /* Fix Resource/Data fork stuff.  Uppercase things where needed */
  32. /* ckzmac.c, Thu Apr 21 17:19, Edit by Bill */
  33. /*  Ignore trying to close an not-openend file, driver does it alot */
  34. /* ckzmac.c, Thu Apr 11 21:18, Edit by Bill */
  35. /*  Catch error in ZOPENO when trying to open an existing file */
  36. /* ckzmac.c, Thu Apr 14 20:07, Edit by Bill */
  37. /*  Translate calls with ZCTERM to go to the console routines */
  38.  
  39. /*
  40.   File ckmfio  --  Kermit file system support for the Macintosh
  41. */
  42.  
  43. /*
  44.  Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  45.  York.  Permission is granted to any individual or institution to use, copy, or
  46.  redistribute this software so long as it is not sold for profit, provided this
  47.  copyright notice is retained.
  48. */
  49.  
  50. /* Definitions of some Unix system commands */
  51.  
  52. char *ckzv = "File support, 5A(081), 24 Jan 92";
  53.  
  54. #include "ckuver.h"            /* Version herald */
  55. char *ckzsys = HERALD;
  56.  
  57. #define DIRCMDSTR "ls"
  58. #define DELCMDSTR "rm"
  59. #define SPCCMDSTR "sp"
  60.  
  61. char *DIRCMD = DIRCMDSTR;    /* For directory listing */
  62. char *DIRCM2 = DIRCMDSTR;    /* For long directory listing */
  63. char *DELCMD = DELCMDSTR;    /* For file deletion */
  64. char *SPACMD = SPCCMDSTR;    /* Space for all available volumes */
  65. char *TYPCMD = "";        /* For typing a file */
  66. char *SPACM2 = "";        /* For space in specified directory */
  67. char *WHOCMD = "";        /* For seeing who's logged in */
  68.  
  69. /*
  70.   Functions (n is one of the predefined file numbers from ckermi.h):
  71.  
  72.    zopeni(n,name)   -- Opens an existing file for input.
  73.    zopeno(n,name)   -- Opens a new file for output.
  74.    zclose(n)        -- Closes a file.
  75.    zchin(n)         -- Gets the next character from an input file.
  76.    zinfill()        -- (re) fill file input buffer, return the first character
  77.    zsout(n,s)       -- Write a null-terminated string to output file, buffered.
  78.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  79.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  80.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  81.    zchki(name)      -- Check if named file exists and is readable, return size.
  82.    zchko(name)      -- Check if named file can be created.
  83.    znewn(name,s)    -- Make a new unique file name based on the given name.
  84.    zdelet(name)     -- Delete the named file.
  85.    zxpand(string)   -- Expands the given wildcard string into a list of files.
  86.    znext(string)    -- Returns the next file from the list in "string".
  87.    zxcmd(cmd)       -- Execute the command in a lower fork.
  88.    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
  89.    zrtol(n1,n2)     -- Convert remote filename into local form.
  90.    zltor(n1,n2)     -- Convert local filename into remote form.
  91.    zchdir(dirnam)   -- Change working directory.
  92.    zhome()          -- Return pointer to home directory name string.
  93.    zkself()         -- Kill self, log out own job.
  94.  */
  95.  
  96. #include "ckcdeb.h"        /* Debug() and tlog() defs */
  97. #include "ckcasc.h"        /* ASCII character symbols */
  98. #include "ckcker.h"        /* Kermit definitions */
  99.  
  100. #include "ckmdef.h"        /* Common Mac module definitions */
  101. #include "ckmres.h"        /* Resource defs */
  102. #include "ckmasm.h"        /* Assembler code */
  103. #include "ckmptp.h"        /* ckm* Prototypes */
  104. #include "ckmwin.h"
  105.  
  106. #ifdef MPW32
  107. #define hfileInfo hFileInfo    /* for compat with newer .h files */
  108. #endif /* MPW32 */
  109.  
  110. /* (PWP) external def. of things used in buffered file input and output */
  111. extern char *zinbuffer, *zoutbuffer;
  112. extern char *zinptr, *zoutptr;
  113. extern int zincnt, zoutcnt;
  114. static long zcnt_written;
  115.  
  116. /* These should all be settable by the File Settings Menu */
  117.  
  118. #define FS_WIND 1        /* file is a text edit buffer */
  119. #define FS_OPEN 2        /* file has been opened */
  120. #define FS_RSRC 4        /* opened in resource fork */
  121. #define FS_DATA 8
  122. #define FS_PIPE 16        /* file is a memory buffer */
  123. #define FS_MACB 32        /* we are sending a file in MacBinary format */
  124.  
  125. MACFILE fp[ZNFILS] = {        /* File information */
  126.     {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  127.     {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  128.     {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}
  129. };
  130.  
  131. static long iflen = -1;            /* Input file length */
  132. static long oflen = -1;            /* Output file length */
  133.  
  134. char printfbuf[256];
  135.  
  136. /****************************************************************************/
  137. /*  Z O P E N I --  Open an existing file for input.
  138.  *
  139.  * The file name has been returned from and the volume reference
  140.  * number set by SFGetFile.
  141.  *
  142.  * Returns:
  143.  *  TRUE: file opened ok
  144.  *  FALSE: some error.
  145.  */
  146. /****************************************************************************/
  147. zopeni (n, name)
  148. int n;
  149. char *name;
  150. {
  151.     int err;
  152.     register MACFILE *fpp;
  153.  
  154.     if (chkfn (n)) {
  155.     printerr ("At zopeni file is already open ", n);
  156.     return (FALSE);
  157.     }
  158.     zincnt = 0;        /* (PWP) clear buffer input count */
  159.     fpp = &fp[n];
  160.  
  161.     if (n == ZCTERM) {        /* Terminal open? */
  162.     if (chkfn (ZIFILE))    /* Check current ZOFILE */
  163.         printerr ("ZIFILE already open...: ", n);
  164.     fp[ZIFILE].fstatus = FS_WIND;    /* redirect... here it is */
  165.     fpp->fstatus = FS_WIND;    /* Indicate this is open too */
  166.     return (conopen ());    /* Return from low level open */
  167.     }
  168.     if (n == ZSYSFN)        /* trying to open a pipe? */
  169.     return (zmxcmd (name));    /* yes... */
  170.  
  171.     if (n == ZIFILE) {        /* opening input file? */
  172.         /* if we are doing MacBinary format */
  173.     if ((filargs.filflg & (FIL_RSRC|FIL_DATA)) == (FIL_RSRC|FIL_DATA)) {
  174.         err = macbinopen(name, fpp);
  175.         if (err == noErr)
  176.             return (TRUE);
  177.         else
  178.             return (ioutil (err));
  179.     } else {
  180.         if (filargs.filflg & FIL_RSRC)    /* and they said resource? */
  181.         err = OpenRF_rdonly (c2p_tmp(name), filargs.filvol,
  182.                      &fpp->frefnum);
  183.         else            /* else some other channel or data */
  184.         err = FSOpen_rdonly (c2p_tmp(name), filargs.filvol,
  185.                      &fpp->frefnum);
  186.         if (err != noErr)        /* check for open error */
  187.         return (ioutil (err));    /* failed... */
  188.     }
  189.     }
  190.  
  191.     fpp->fstatus = FS_OPEN | (    /* set flags */
  192.                (filargs.filflg & FIL_RSRC) ? FS_RSRC : FS_DATA);
  193.  
  194.     GetEOF (fpp->frefnum, &filargs.filsiz);    /* set size for screen */
  195.  
  196. #ifdef COMMENT
  197.     fsize = filargs.filsiz;    /* PWP: set size for screen */
  198. #endif
  199.  
  200.     return (TRUE);        /* Return success */
  201. }                /* zopeni */
  202.  
  203. MBHead filHead;
  204. static char MBname[64];
  205.  
  206. void
  207. bzero (b, n)
  208. register char *b;
  209. register int n;
  210. {
  211.     while (n-- > 0)
  212.     *b++ = 0;
  213. }
  214.  
  215. void
  216. bcopy (a, b, n)
  217. register char *a, *b;
  218. register int n;
  219. {
  220.     while (n-- > 0)
  221.     *b++ = *a++;
  222. }
  223.  
  224. /* these next three taken from NCSA Telnet 2.2 */
  225. int
  226. GetFileInfo(vol,name,iop)
  227. short vol;
  228. char *name;
  229. ParamBlockRec *iop;
  230. {
  231.     char thename[64];
  232.     
  233.     strncpy (thename, name, 64);    /* make my own copy of this */
  234.     thename[63] = '\0';
  235.     c2pstr(thename);
  236.     
  237.     iop->fileParam.ioNamePtr = thename;
  238.     iop->fileParam.ioVRefNum=vol;
  239.     iop->fileParam.ioFVersNum=iop->fileParam.ioFDirIndex=0;
  240.     PBGetFInfo(iop, FALSE);
  241.     return (iop->fileParam.ioResult);
  242. }
  243.  
  244. int
  245. SetFileInfo(vol,name,iop)
  246. short vol;
  247. char *name;
  248. ParamBlockRec *iop;
  249. {
  250.     char thename[64];
  251.     
  252.     strncpy (thename, name, 64);    /* make my own copy of this */
  253.     thename[63] = '\0';
  254.     c2pstr(thename);
  255.     
  256.     iop->fileParam.ioNamePtr = thename;
  257.     iop->fileParam.ioVRefNum=vol;
  258.     iop->fileParam.ioFVersNum=iop->fileParam.ioFDirIndex=0;
  259.     PBSetFInfo(iop, FALSE);
  260.     return (iop->fileParam.ioResult);
  261. }
  262.  
  263. int
  264. MakeTextFile(vol,name,iop)
  265. short vol;
  266. char *name;
  267. ParamBlockRec *iop;
  268. {
  269.     GetFileInfo(vol,name,iop);
  270.     iop->fileParam.ioFlFndrInfo.fdType='TEXT';
  271.     iop->fileParam.ioFlFndrInfo.fdCreator='EDIT';
  272.     SetFileInfo(vol,name,iop);
  273.     return (iop->fileParam.ioResult);
  274. }
  275.  
  276. int
  277. macbinopen(name, fpp)
  278. char *name;
  279. MACFILE *fpp;
  280. {
  281.     ParamBlockRec finfo;
  282.     int err;
  283.     
  284.     /* open first fork of name for reading and fill input buffer
  285.        with MacBinary header */
  286.     /* save file name for later */
  287.     strncpy (MBname, name, 64);
  288.     MBname[64] = 0;
  289.     
  290.     /* clear out the header */
  291.     bzero (&filHead, sizeof(MBHead));
  292.     
  293.     /* put the name into place */
  294.     strncpy (&filHead.name[0], name, 64);
  295.     filHead.name[63] = '\0';
  296.     c2pstr(filHead.name);
  297.     
  298.     /* get the file info */
  299.     if ((err = GetFileInfo( filargs.filvol, name, &finfo)) != noErr) {
  300.     printerr("macbinopen: problem with GetFileInfo", err);
  301.     return (err);
  302.     }
  303.  
  304.     bcopy( &finfo.fileParam.ioFlFndrInfo, &filHead.type[0], sizeof(FInfo) );
  305.     filHead.protected = (filHead.zero2 & 0x40)?1:0;
  306.     filHead.zero2 = 0;
  307.     bcopy(&finfo.fileParam.ioFlLgLen, &filHead.dflen[0], 4);
  308.     bcopy(&finfo.fileParam.ioFlRLgLen, &filHead.rflen[0], 4);
  309.     bcopy(&finfo.fileParam.ioFlCrDat, &filHead.cdate[0], 4);
  310.     bcopy(&finfo.fileParam.ioFlMdDat, &filHead.mdate[0], 4);
  311.  
  312.     filargs.filsiz=finfo.fileParam.ioFlLgLen;
  313.     filargs.rsrcsiz=finfo.fileParam.ioFlRLgLen;
  314.     
  315. #ifdef COMMENT
  316.     fsize = ((filargs.filsiz + 127) & ~127)
  317.         + ((filargs.rsrcsiz + 127) & ~127)
  318.         + 128;
  319. #endif
  320.  
  321.     bcopy (&filHead, zinbuffer, 128);    /* put header in xfer buffer */
  322.     zincnt = 128;            /* init buffer to 128 to send */
  323.     zinptr = zinbuffer;       /* set pointer to beginning, (== &zinbuffer[0]) */
  324.  
  325.     if (filargs.filsiz <= 0) {
  326.     /* no data fork, open the resource fork */
  327.     if ((err = OpenRF_rdonly(c2p_tmp(name),
  328.               filargs.filvol, &fpp->frefnum)) != noErr) {
  329.          printerr("macbinopen: problem with OpenRF", err);
  330.          return (err);
  331.     }
  332.     fpp->fstatus = FS_OPEN | FS_RSRC | FS_MACB;
  333.     } else {
  334.     /* we do the data fork first, then the resource fork */
  335.     if ((err = FSOpen_rdonly (c2p_tmp(name),
  336.                filargs.filvol, &fpp->frefnum)) != noErr) {
  337.          printerr("macbinopen: problem with FSOpen", err);
  338.          return (err);
  339.     }
  340.     fpp->fstatus = FS_OPEN | FS_DATA | FS_MACB;
  341.     }
  342.     return (noErr);
  343. }
  344.  
  345. /* is this a MacBinary I header -- see standard-macbinary-ii.txt (on Sumex) */
  346. is_macbinary(h)
  347. MBHead h;
  348. {
  349.     long l;
  350.     
  351.     if ((h.zero1 != 0) || (h.zero2 != 0) || (h.zero3 != 0)) {
  352.     printerr("zeros", 0);
  353.         return (0);
  354.     }
  355.     if ((h.name[0] == 0) || (h.name[0] & 0xc0)) {
  356.     printerr("name length", h.name[0]);
  357.         return (0);
  358.     }
  359.     bcopy (&h.dflen[0], &l, 4);
  360.     if ((l < 0) || (l > 0x7fffff)) {
  361.     printerr("data length", l);
  362.         return (0);
  363.     }
  364.     bcopy (&h.rflen[0], &l, 4);
  365.     if ((l < 0) || (l > 0x7fffff))  {
  366.     printerr("rsrc length", l);
  367.         return (0);
  368.     }
  369. #ifdef COMMENT
  370.     /* MacBinary II uses this area for more stuff, so don't check it */
  371.     for (i = 2; i < 27; i++) {
  372.         if (h.filler[i] != 0) {
  373.         printerr("filler index:", i);
  374.         return (0);
  375.     }
  376.     }
  377. #endif /* COMMENT */
  378.     return (1);
  379. }
  380.  
  381.  
  382. /****************************************************************************/
  383. /*  Z O P E N O  --  Open a new file for output.
  384.  *
  385.  * Returns:
  386.  *  TRUE: File opened ok
  387.  *  FALSE: some error has occured or channel occupied.
  388.  *
  389.  */
  390. /****************************************************************************/
  391.  
  392. short zopo_vrefnum = 0;        /* a hack for where to put the file */
  393.  
  394. zopeno (n, name, zz, fcb)
  395.     int n;
  396.     char *name;
  397.     struct zattr *zz;
  398.     struct filinfo *fcb;
  399. {
  400.     OSType forktext, authortext;
  401.     int err;
  402.     FInfo finfo;
  403.     register MACFILE *fpp;
  404.     short the_vrefnum;
  405.     
  406. #ifdef notdef
  407.     if ((zz != NULL) || (fcb != NULL)) {
  408.     printerr ("zopeno: zz or fcb not NULL", 0);
  409.     return(FALSE);
  410.     }
  411. #endif
  412.  
  413.     if (chkfn (n)) {
  414.     printerr ("zopeno - file is already open: ", n);
  415.     return (FALSE);
  416.     }
  417.     fpp = &fp[n];
  418.  
  419.     if (n == ZDFILE) {            /* debugging open? */
  420.     if (chkfn (n))        /* Check current ZOFILE */
  421.         printerr ("Console already open...: ", n);
  422.     fp[n].fstatus = FS_WIND;    /* yes, redirect... here it is */
  423.     return (conopen ());    /* Return from low level open */
  424.     }
  425.     if (n == ZCTERM || n == ZSTDIO) {    /* Terminal open? */
  426.     if (chkfn (ZOFILE))    /* Check current ZOFILE */
  427.         printerr ("ZOFILE already open...: ", n);
  428.     fp[ZOFILE].fstatus = FS_WIND;    /* yes, redirect... here it is */
  429.     fpp->fstatus = FS_WIND;    /* Indicate this is open too */
  430.     zoutcnt = 0;        /* (PWP) reset output buffer */
  431.     zoutptr = zoutbuffer;
  432.     return (conopen ());    /* Return from low level open */
  433.     }
  434.     if (n == ZOFILE) {
  435.     zoutcnt = 0;        /* (PWP) reset output buffer */
  436.     zoutptr = zoutbuffer;
  437.     if ((filargs.filflg & (FIL_RSRC|FIL_DATA)) == (FIL_RSRC|FIL_DATA)) {
  438.         /* if MacBinary */
  439.         forktext = 'TEXT';        /* a text file, because we don't */
  440.         authortext = '????';    /* know what else to do with it. */
  441.     } else if (filargs.filflg & FIL_RSRC) {
  442.         forktext = 'APPL';
  443.         authortext = '????';
  444.     } else {
  445.         forktext = 'TEXT';        /* Make fork reflect fork choice */
  446.         authortext = 'MACA';    /* set creator to "MacWrite" */
  447.     }
  448.     the_vrefnum = filargs.filvol;
  449.     }
  450.     else
  451.     {                /* a file, but not the transfer output file */
  452.     if (zopo_vrefnum)
  453.         the_vrefnum = zopo_vrefnum;
  454.     else
  455.         the_vrefnum = filargs.filvol;    /* same as for transfers */
  456.     zopo_vrefnum = 0;        /* we've now used this */
  457.     }
  458.  
  459.     err = Create (c2p_tmp(name), the_vrefnum, authortext, forktext);
  460.     if (err == dupFNErr) {    /* duplicate file? */
  461.     if (!ioutil (FSDelete (c2p_tmp(name),    /* Try to delete it */
  462.                    the_vrefnum)))    /* checking for failure */
  463.         return (FALSE);    /* failed... */
  464.     err = Create (c2p_tmp(name), the_vrefnum,    /* recreate */
  465.               authortext, forktext);
  466.     }
  467.     if (err != noErr)        /* some error? */
  468.     return (ioutil (err));    /* yes, do message and return */
  469.  
  470.     if (n == ZOFILE) {        /* is it our transferred file? */
  471.     /* set file's folder from filargs.filfldr which is either the */
  472.     /* applications folder or the settings file folder */
  473.     
  474.     /* read current finder info */
  475.     GetFInfo (c2p_tmp(name), the_vrefnum, &finfo);
  476.     finfo.fdFldr = filargs.filfldr;    /* set new folder */
  477.     /* and tell system about it */
  478.     SetFInfo (c2p_tmp(name), the_vrefnum, &finfo);
  479.  
  480.     zcnt_written = 0;
  481.         /* if we are doing MacBinary format */
  482.     if ((filargs.filflg & (FIL_RSRC|FIL_DATA)) == (FIL_RSRC|FIL_DATA)) {
  483.         /* save file name for later */
  484.         bzero (MBname, 64);        /* clear name buffer */
  485.         strncpy (MBname, name, 64);
  486.         MBname[64] = 0;
  487.         /* we delay opening any forks until we have the MacBin header */
  488.         fp[n].fstatus = FS_OPEN | FS_MACB;    /* neither DATA nor RSRC yet */
  489.         return (TRUE);        /* done ok */
  490.     } else {     /* not MacBinary */
  491.         if (filargs.filflg & FIL_RSRC) /* want to use resource fork?  */
  492.         err = OpenRF (c2p_tmp(name), the_vrefnum,    /* yes... */
  493.               &fpp->frefnum);
  494.         else            /* else data, or some other file */
  495.         err = FSOpen (c2p_tmp(name), the_vrefnum, &fpp->frefnum);
  496.     }
  497.     } else {
  498.     err = FSOpen (c2p_tmp(name), the_vrefnum, &fpp->frefnum);
  499.     }
  500.     
  501.     if (err != noErr)        /* able to open? */
  502.     return (ioutil (err));    /* no. fail return now */
  503.  
  504.     if (n == ZOFILE) {        /* is it our transferred file? */
  505.     fp[n].fstatus = FS_OPEN |
  506.         ((filargs.filflg & FIL_RSRC) ? FS_RSRC : FS_DATA);
  507.     } else {
  508.     fp[n].fstatus = FS_OPEN | FS_DATA;
  509.     }
  510.     
  511.     return (TRUE);        /* done ok */
  512. }                /* zopeno */
  513.  
  514. /***********************************************************************
  515.  * mbcl_cleanup -- do stuff after closeing an open (for recipt) macbinary file.
  516.  */
  517. mbcl_cleanup()
  518. {
  519.     int err = noErr, e2 = 0;
  520.     ParamBlockRec finfo;
  521.     Point old_location;
  522.  
  523.     if (!cxseen && !czseen &&
  524.     (zcnt_written > ((filargs.rsrcsiz + 127) & ~127)) ||
  525.     (zcnt_written < filargs.rsrcsiz)) {
  526.     sprintf(printfbuf, "Resource fork size mismatch: should be %d is %d",
  527.         filargs.rsrcsiz, zcnt_written);
  528.     printerr(printfbuf, 0);
  529.     }
  530.  
  531.     if ((err = GetFileInfo(filargs.filvol, MBname, &finfo)) != noErr) {
  532.     sprintf(printfbuf, "Could not GetFileInfo on \"%s\": error %d",
  533.         MBname, err);
  534.     printerr(printfbuf,0);
  535.     } else {
  536.     old_location = finfo.fileParam.ioFlFndrInfo.fdLocation;
  537.     
  538.     filHead.protected &= 01;    /* nuke all but low order bit */
  539.     
  540.     bcopy(&filHead.type[0], &finfo.fileParam.ioFlFndrInfo, sizeof(FInfo));
  541.     bcopy(&filHead.cdate[0], &finfo.fileParam.ioFlCrDat, 4);
  542.     bcopy(&filHead.mdate[0], &finfo.fileParam.ioFlMdDat, 4);
  543.  
  544.     /* As per the MacBinary II doc, I clear the following flags:
  545.      *
  546.      *  0 - Set if file/folder is on the desktop (Finder 5.0 and later)
  547.      *  1 - bFOwnAppl (used internally)
  548.      *  8 - Inited (seen by Finder)
  549.      *  9 - Changed (used internally by Finder)
  550.      * 10 - Busy (copied from File System busy bit)
  551.      */
  552.     finfo.fileParam.ioFlFndrInfo.fdFlags &= 0xf8fc;
  553.  
  554.     /* set new folder */
  555.     /* finfo.fileParam.ioFlFndrInfo.fdFldr = filargs.filfldr; */
  556.     finfo.fileParam.ioFlFndrInfo.fdFldr = 0;    /* set new folder */
  557.     /* old_location */
  558.     finfo.fileParam.ioFlFndrInfo.fdLocation = old_location;
  559.     
  560.     if (finfo.fileParam.ioFlLgLen != filargs.filsiz) {
  561.         sprintf(printfbuf,
  562.             "%s: Data fork size mismatch: should be %d is %d",
  563.         MBname, filargs.filsiz, finfo.fileParam.ioFlLgLen);
  564.         printerr(printfbuf, 0);
  565.     }
  566.     if (finfo.fileParam.ioFlRLgLen != filargs.rsrcsiz) {
  567.         sprintf(printfbuf,
  568.             "%s: Resource fork size mismatch: should be %d is %d",
  569.         MBname, filargs.rsrcsiz, finfo.fileParam.ioFlRLgLen);
  570.         printerr(printfbuf, 0);
  571.     }
  572.     /* finfo.fileParam.ioFlRLgLen=out->rlen; */
  573.     /* finfo.fileParam.ioFlLgLen =out->dlen; */
  574.  
  575.     if ((err = SetFileInfo(filargs.filvol, MBname, &finfo)) != noErr)
  576.         printerr("Could not SetFileInfo:", err);
  577.     /* make sure the new data got to disk */
  578.     
  579.     /* try to give it the name encoded in the MacBinary header */
  580.     err = Rename(c2p_tmp(MBname), filargs.filvol, c2p_tmp2(filHead.name));
  581.     if (err != noErr)
  582.         screen(SCR_WM, 0, 0l, "Can't rename file to its MacBinary name.");
  583.  
  584.     err = FlushVol (NILPTR, filargs.filvol);
  585.     }
  586.  
  587.     return (err);
  588. }
  589.  
  590.  
  591. /****************************************************************************/
  592. /*  Z C L O S E  --  Close the given file.
  593.  *
  594.  * Returns:
  595.  *  TRUE: file closed ok.
  596.  *  FLASE: some error has occured.
  597.  *
  598.  */
  599. /****************************************************************************/
  600. zclose (n)
  601. int n;
  602. {
  603.     int err = noErr, e2 = 0;
  604.     register MACFILE *fpp;
  605.  
  606.     if (!chkfn (n))        /* is it opened? */
  607.     return (FALSE);        /* no return now */
  608.  
  609.     if ((n == ZOFILE) && (zoutcnt > 0))    /* (PWP) output leftovers */
  610.     e2 = zoutdump();
  611.  
  612.     fpp = &fp[n];
  613.  
  614.     if (fpp->fstatus == FS_WIND) {    /* is this a window? */
  615.     fp[ZCTERM].fstatus = 0;        /* yes, clear ZCTERM */
  616.  
  617.     } else if (fpp->fstatus == FS_PIPE) {    /* is this a pipe? */
  618.     fp[ZSYSFN].fstatus = 0;    /* yes, no pipe now, clear ZSYSFN */
  619.  
  620.     } else if (n == ZIFILE) {    /* Sending this file? */
  621.     err = FSClose (fpp->frefnum);    /* use OS close */
  622.     if (err != noErr)
  623.         printerr("zclose(): problem closing input file:", err);
  624.         
  625.     } else if (n == ZOFILE) {        /* recieving this file */
  626.     if (fpp->fstatus & FS_MACB) {   /* if MacBinary format */
  627.         if (fpp->fstatus & FS_OPEN) {
  628.             printerr(
  629.         "zclose(): MacBinary botched: this file should NOT still be open", 0);
  630.         err = FSClose (fpp->frefnum);    /* close it just to be safe */
  631.     
  632.         if (err == noErr)    /* and if that worked */
  633.             /* PWP: the above if should be ==, NOT != !!!!! */
  634.             /* flush buffers in case write worked */
  635.             err = FlushVol (NILPTR, filargs.filvol);
  636.         if (err != noErr)
  637.             printerr("zclose(): problem closing/flushing output file:",
  638.                  err);
  639.         }
  640.     } else {
  641.         err = FSClose (fpp->frefnum);    /* else use OS close */
  642.     
  643.         if (err != noErr)
  644.         printerr("zclose(): problem closing output file:", err);
  645.  
  646.         /* flush buffers in case write worked */
  647.         err = FlushVol (NILPTR, filargs.filvol);
  648.  
  649.         if (err != noErr)
  650.         printerr("zclose(): problem flushing output disk:", err);
  651.     }
  652.     if (fpp->fstatus & FS_MACB) {   /* if MacBinary format */
  653.         err = mbcl_cleanup();
  654.     }
  655.     } else if (n == ZWFILE) {        /* if opened by a command */
  656.     err = FSClose (fpp->frefnum);    /* else use OS close */
  657.     
  658.     if (err != noErr)
  659.         printerr("zclose(): problem closing output file:", err);
  660.     
  661.     /* flush buffers in case write worked */
  662.     err = FlushVol (NILPTR, filargs.filvol);
  663.  
  664.     if (err != noErr)
  665.         printerr("zclose(): problem flushing output disk:", err);
  666.     } else {
  667.     printerr("zclose(): I don't know what kind of file this is:", n);
  668.     }
  669.     
  670.     fpp->fstatus = 0;        /* clear out status word */
  671.     if (n == ZOFILE || n == ZIFILE)    /* turn off both flags */
  672.     filargs.filflg &= ~(FIL_RSRC | FIL_DATA);
  673.  
  674.     iflen = -1;            /* Invalidate file length */
  675.  
  676.     if (e2 < 0) {
  677.     (void) ioutil (err);
  678.     return (FALSE);
  679.     } else {
  680.     return (ioutil (err));    /* return according to io operations */
  681.     }
  682. }                /* zclose */
  683.  
  684.  
  685.  
  686. /****************************************************************************/
  687. /*  Z C H I N  --  Get a character from the input file.
  688.  *
  689.  * Returns:
  690.  *  0: Ok
  691.  * -1: EOF (or other error).
  692.  *
  693.  */
  694. /****************************************************************************/
  695. zchin (n, c)
  696. int n;
  697. char *c;
  698. {
  699.     int err;
  700.     long rdcnt;            /* pascal long */
  701.     register MACFILE *fpp;
  702.     register MACPIPE *pipe;
  703.  
  704.     if (n == ZIFILE)
  705.     return (zminchar());    /* (PWP) go through the macro */
  706.  
  707.     if (!chkfn (n))
  708.     return (0);
  709.  
  710.     fpp = &fp[n];
  711.  
  712.     if (fpp->fstatus == FS_WIND) {    /* a window? */
  713.     printerr ("zchin called for FS_WIND file: ", n);
  714.     return (0);
  715.     }
  716.     if (fpp->fstatus == FS_PIPE) {    /* a pipe? */
  717.     pipe = fpp->fpipe;
  718.  
  719.     if (pipe->charsleft <= 0) {    /* test for characters left */
  720.         pipe->currptr = pipe->pipebuf;    /* restart at the beginning
  721.                          * of the buffer */
  722.  
  723.         if (pipe->refill != NILPROC) {    /* refill the pipe if
  724.                          * possible */
  725.         saveA0 ();    /* push content of A0 to stack */
  726.         /* load the content of refill to A0 */
  727.         loadA0 ((char *) *(pipe->refill)); 
  728.         
  729.         execute ();    /* call the refill procedure */
  730.         restoreA0 ();    /* get A0 back from the stack */
  731.         } else
  732.         *(pipe->currptr) = '\0'; /* make it end otherwise */
  733.     }
  734.     if (*(pipe->currptr) == '\0')    /* is this eo-pipe? */
  735.         return (-1);    /* yes, fail return */
  736.  
  737.     *c = *(pipe->currptr)++;/* read character */
  738.     (pipe->charsleft)--;    /* decrement characters left */
  739.  
  740.     return (0);        /* success */
  741.     }
  742.     rdcnt = 1;
  743.     err = FSRead (fpp->frefnum, &rdcnt, c);
  744.     if (err == eofErr)
  745.     return (-1);        /* Failure return */
  746.     return (ioutil (err) ? 0 : -1);    /* success or unknown failure */
  747. }                /* zchin */
  748.  
  749. /*  Z S I N L  --  Read a line from a file  */
  750.  
  751. /*
  752.   Writes the line into the address provided by the caller.
  753.   n is the Kermit "channel number".
  754.   Writing terminates when newline is encountered, newline is not copied.
  755.   Writing also terminates upon EOF or if length x is exhausted.
  756.   Returns 0 on success, -1 on EOF or error.
  757. */
  758. int
  759. zsinl(n,s,x) int n, x; char *s; {
  760.     int a, z = 0;
  761.  
  762.     if (chkfn(n) < 1) {            /* Make sure file is open */
  763.     return(-1);
  764.     }
  765.     a = -1;
  766.     while (x--) {
  767. #ifndef NLCHAR
  768.     int old;
  769.     old = a;            /* Previous character */
  770. #endif
  771.     if (zchin(n,&a) < 0) {        /* Read a character from the file */
  772.         z = -1;
  773.         break;
  774.     }
  775. #ifdef NLCHAR
  776.     if (a == (char) NLCHAR) break;    /* Single-character line terminator */
  777. #else
  778.     if (a == '\r') continue;    /* CRLF line terminator */
  779.     if (old == '\r') {
  780.         if (a == '\n') break;
  781.         else *s++ = '\r';
  782.     }
  783. #endif /* NLCHAR */
  784.     *s = a;
  785.     s++;
  786.     }
  787.     *s = '\0';
  788.     return(z);
  789. }
  790.  
  791.  
  792.  
  793. /*
  794.  * (PWP) (re)fill the buffered input buffer with data.  All file
  795.  * input should go through this routine, usually by calling the
  796.  * zminchar() macro
  797.  */
  798.  
  799. zinfill() {
  800.     int err;
  801.     long rdcnt;            /* pascal long */
  802.     register MACFILE *fpp;
  803.     char *cp;
  804.  
  805.     fpp = &fp[ZIFILE];
  806.  
  807.     /* if not an open file; just get one character */
  808.     if (!(fpp->fstatus & FS_OPEN)) {
  809.     zincnt = 0;
  810.     if (zchin (ZIFILE, zinbuffer) < 0)
  811.         return (-1);
  812.     return (zinbuffer[0]);
  813.     }
  814.     
  815.     rdcnt = INBUFSIZE;
  816.     err = FSRead (fpp->frefnum, &rdcnt, zinbuffer);
  817.     zincnt = rdcnt;            /* set number actually read */
  818.  
  819.     /* check for any errors */
  820.     if ((err != noErr) && (err != eofErr) && (!ioutil(err)))
  821.     return (-1);
  822.  
  823.     /*
  824.      * PWP: FSRead will return eofErr when it reads the last
  825.      * partial block of data.  If rdcnt > 0, then we still have
  826.      * the last bit of the file to send out...
  827.      */
  828.     if (err == eofErr) {
  829.     if (rdcnt == 0) {    /* if actual EOF */
  830.         return (-1);        /* EOF return */
  831.     } else {        /* last real block */
  832.         if (fpp->fstatus & FS_MACB) {    /* if MacBinary format */
  833.         /* pad out things */
  834.         rdcnt = (128 - (filargs.filsiz % 128)) % 128;
  835.  
  836.         /* for (cp = &zinbuffer[zincnt]; rdcnt > 0; rdcnt--) */
  837.         for (cp = zinbuffer + zincnt; rdcnt > 0; rdcnt--)
  838.             *cp++ = 0;
  839.             
  840.         zincnt = (zincnt + 127) & ~127;    /* pad out to 128 bytes */
  841.             
  842.         if (fpp->fstatus & FS_DATA) { /* if we were doing data fork */
  843.             fpp->fstatus &= ~FS_DATA;
  844.             
  845.             if (filargs.rsrcsiz != 0) {    /* if a resource fork */
  846.             if ((err = FSClose (fpp->frefnum)) != noErr) {
  847.                 printerr("zinfill: trouble closing data fork:",
  848.                      err);
  849.                 return (-1);
  850.             }
  851.  
  852.             /* open the resource fork 'cause we do that next */
  853.             if ((err = OpenRF_rdonly (c2p_tmp(MBname), filargs.filvol,
  854.                                &fpp->frefnum)) != noErr) {
  855.                 printerr("zinfill: trouble opening rsrc fork:",
  856.                      err);
  857.                 return (-1);
  858.             }
  859.  
  860.             /* in case anyone else needs to know */
  861.             fpp->fstatus |= FS_RSRC;
  862.             }
  863.         }
  864.         }
  865.     }
  866.     }
  867.     
  868.     zinptr = zinbuffer;       /* set pointer to beginning, (== &zinbuffer[0]) */
  869.     zincnt--;            /* one less char in buffer */
  870.     return((int)(*zinptr++) & 0377); /* because we return the first */
  871. }
  872.  
  873.  
  874. /****************************************************************************/
  875. /*  Z S O U T  --  Write a string to the given file, buffered.
  876.  *
  877.  * Returns:
  878.  *  0: OK
  879.  * -1: Error
  880.  *
  881.  */
  882. /****************************************************************************/
  883. zsout (n, s)
  884. int n;
  885. char *s;
  886. {
  887.     long wrcnt;            /* pascal long */
  888.  
  889.     if (n == ZCTERM || fp[n].fstatus == FS_WIND)
  890.     return (conol (s));
  891.  
  892.     wrcnt = (long) strlen (s);
  893.     return (ioutil (FSWrite (fp[n].frefnum, &wrcnt, s)) ? 0 : -1);
  894. }                /* zsout */
  895.  
  896.  
  897.  
  898. /****************************************************************************/
  899. /*  Z S O U T L  --  Write string to file, with line terminator, buffered.
  900.  *
  901.  * Returns:
  902.  *  0: OK
  903.  * -1: Error
  904.  *
  905.  */
  906. /****************************************************************************/
  907. zsoutl (n, s)
  908. int n;
  909. char *s;
  910. {
  911.     long wrcnt;            /* pascal long */
  912.     int err;
  913.  
  914.     if (n == ZCTERM || fp[n].fstatus == FS_WIND)
  915.     return (conoll (s));
  916.  
  917.     wrcnt = (long) strlen (s);
  918.     err = FSWrite (fp[n].frefnum, &wrcnt, s);
  919.     if (err == noErr) {
  920.     wrcnt = 2;
  921.     err = FSWrite (fp[n].frefnum, &wrcnt, "\r\n");
  922.     }
  923.     return (ioutil (err) ? 0 : -1);
  924. }                /* zsoutl */
  925.  
  926.  
  927.  
  928. /****************************************************************************/
  929. /*  Z S O U T X  --  Write x characters to file, unbuffered.
  930.  *
  931.  * Returns:
  932.  *  0: OK
  933.  * -1: Error
  934.  */
  935. /****************************************************************************/
  936. zsoutx (n, s, x)
  937. int n, x;
  938. char *s;
  939. {
  940.     long size;
  941.  
  942.     if (n == ZCTERM || fp[n].fstatus == FS_WIND)
  943.     return (conxo (x, s));
  944.  
  945.     size = x;
  946.     return (ioutil (FSWrite (fp[n].frefnum, &size, s)) ? 0 : -1);
  947. }                /* zsoutx */
  948.  
  949.  
  950.  
  951. /****************************************************************************/
  952. /*  Z C H O U T  --  Add a character to the given file. */
  953. /*                        */
  954. /* Returns:        */
  955. /*  0: OK            */
  956. /* -1: Error    */
  957. /****************************************************************************/
  958. zchout (n, c)
  959. int n;
  960. char c;
  961. {
  962.     long wrcnt;            /* pascal long */
  963.     int err;
  964.  
  965.     if (n == ZCTERM || fp[n].fstatus == FS_WIND) {
  966.     conoc (c);        /* Then send to console routine */
  967.     return (0);        /* Then send to console routine */
  968.     }
  969.     
  970.     if (n == ZOFILE)    /* (PWP) just in case */
  971.     return (zmchout(c));
  972.     
  973.     wrcnt = 1;
  974.     err = FSWrite (fp[n].frefnum, &wrcnt, &c);
  975.     if (err != noErr)        /* error occured? */
  976.     sstate = 'a';        /* yes, abort protocol */
  977.     return (ioutil (err) ? 0 : -1);    /* else return code */
  978. }                /* zchout */
  979.  
  980.  
  981. /****************************************************************************
  982.  * (PWP) Tell the mac to actually write the contents of the file to disk.
  983.  * this avoids the problem of the Mac waiting around until it has filled
  984.  * the disk cache and then flushing all of it at once (which takes several
  985.  * seconds).
  986.  */
  987. void
  988. flush_file_in_background(int frefnum)
  989. {
  990.     int err;
  991.     ParamBlockRec info;
  992.  
  993.     info.ioParam.ioRefNum = frefnum;    /* file descriptor */
  994.     info.ioParam.ioCompletion = NULL;    /* no completion routine to call */
  995.     
  996.     err = PBFlushFile (&info, TRUE);    /* tell system to flush that file */
  997.  
  998.     if (err != noErr)        /* any error? */
  999.     printerr ("flush_file_in_background failed: ", err);
  1000.                 /* tell me about it */
  1001. }
  1002.  
  1003.  
  1004. /* (PWP) buffered character output routine to speed up file IO */
  1005. zoutdump()
  1006. {
  1007.     long wrcnt, tmpcnt;            /* pascal long */
  1008.     int err;
  1009.     char *outp;
  1010.     
  1011.     debug(F101,"  zoutdump: zoutcnt","",zoutcnt);
  1012.  
  1013.     if ((zoutcnt < 0) || (zoutcnt > OBUFSIZE)) {
  1014.     printerr("zoutdump(): zoutcnt out of range", zoutcnt);
  1015.     zoutcnt = 0;
  1016.     zoutptr = zoutbuffer;
  1017.     return (-1);
  1018.     }
  1019.     
  1020.     wrcnt = (long) zoutcnt;
  1021.     if (wrcnt <= 0)
  1022.         return (0);        /* nothing to do */
  1023.  
  1024.     if (fp[ZOFILE].fstatus == FS_WIND) {    /* if console output */
  1025.     conxo(zoutcnt, zoutbuffer);
  1026.     zoutcnt = 0;
  1027.     zoutptr = zoutbuffer;
  1028.     return(0);
  1029.     }
  1030.  
  1031.     outp = zoutbuffer;
  1032.     
  1033.     if (fp[ZOFILE].fstatus & FS_MACB) {    /* if MacBinary format */
  1034.     /* if done with both Data and Rsrc */
  1035.     if (!(fp[ZOFILE].fstatus & FS_OPEN)) {
  1036.         /* keep track of how much leftover we got */
  1037.         zcnt_written += wrcnt;
  1038.         zoutcnt = 0;
  1039.         zoutptr = zoutbuffer;
  1040.         return (0);        /* toss 'em */
  1041.     }
  1042.     /* looking for header */
  1043.     if (!(fp[ZOFILE].fstatus & (FS_RSRC | FS_DATA))) {
  1044.         if (zoutcnt < 128)    /* we don't have all of the header yet */
  1045.         return (0);
  1046.  
  1047.         bcopy(zoutbuffer, &filHead, 128);
  1048.  
  1049.         if (!is_macbinary(filHead)) {
  1050.         screen(SCR_WM, 0, 0l,
  1051.                "Not a MacBinary file, reverting to binary, data fork");
  1052.         screen(SCR_AN,0,0l,MBname); /* stop saying MacBinary mode */
  1053.         err = FSOpen (c2p_tmp(MBname),
  1054.                   filargs.filvol,
  1055.                   &fp[ZOFILE].frefnum);
  1056.         if (err != noErr) {
  1057.             printerr("zoutdump(): trouble with FSOpen:", err);
  1058.             (void) ioutil(err);
  1059.             return (-1);
  1060.         }
  1061.         fp[ZOFILE].fstatus = FS_OPEN | FS_DATA;    /* unset FS_MACB */
  1062.         goto norm_file;
  1063.         }
  1064.  
  1065.         /* adjust pointers */
  1066.         wrcnt = zoutcnt - 128;
  1067.         outp = &zoutbuffer[128];
  1068.         
  1069.         /* get the sizes from header */
  1070.         bcopy(&filHead.dflen[0], &filargs.filsiz, 4);
  1071.         bcopy(&filHead.rflen[0], &filargs.rsrcsiz, 4);
  1072.     
  1073.         if (filargs.filsiz > 0) {    /* is there a data fork?  */
  1074.         err = FSOpen (c2p_tmp(MBname),
  1075.                   filargs.filvol, &fp[ZOFILE].frefnum);
  1076.         if (err != noErr) printerr("zoutdump(): trouble with FSOpen:",
  1077.                        err);
  1078.         fp[ZOFILE].fstatus |= FS_DATA;
  1079.         } else {            /* else data, or some other file */
  1080.         err = OpenRF (c2p_tmp(MBname),
  1081.                   filargs.filvol, &fp[ZOFILE].frefnum);
  1082.         if (err != noErr)
  1083.           printerr("zoutdump(): trouble with OpenRF:", err);
  1084.         fp[ZOFILE].fstatus |= FS_RSRC;
  1085.         }
  1086.         
  1087.         if (err != noErr) {
  1088.         sstate = 'a';        /* yes, abort protocol */
  1089.         return (ioutil (err) ? 0 : -1);
  1090.         }
  1091.         
  1092.         zcnt_written = 0;
  1093.  
  1094.         /* screen(SCR_AN,0,0l,MBname); */ /* Make screen say MacBinary */
  1095.         
  1096.         if (wrcnt <= 0) {    /* if nothing to write */
  1097.         zoutcnt = 0;
  1098.         zoutptr = zoutbuffer;
  1099.         return (0);    /* we are done this time */
  1100.         }
  1101.     }
  1102.     
  1103.     /* can't be "else if" here, above if may feed this if */
  1104.     if (fp[ZOFILE].fstatus & FS_DATA) {    /* if doing data fork */
  1105.         if (zcnt_written + wrcnt >= filargs.filsiz) {
  1106.         tmpcnt = wrcnt;        /* save old amount of data */
  1107.  
  1108.         /* figure how how much we really should write */
  1109.         wrcnt = filargs.filsiz - zcnt_written;
  1110.         err = FSWrite (fp[ZOFILE].frefnum, &wrcnt, outp);
  1111.         zcnt_written += wrcnt;
  1112.         outp += wrcnt;
  1113.         
  1114.         wrcnt = tmpcnt - wrcnt;    /* adjust to reflect the write */
  1115.         
  1116.         /* close data fork, open rsrc fork */
  1117.         if (err == noErr)
  1118.             err = FSClose (fp[ZOFILE].frefnum);
  1119.         if (err == noErr)    /* and if that worked */
  1120.             err = FlushVol (NILPTR,    /* flush  OS buffers */
  1121.                 filargs.filvol);
  1122.         if (err == noErr)
  1123.             err = OpenRF (c2p_tmp(MBname), filargs.filvol, /* yes... */
  1124.                   &fp[ZOFILE].frefnum);
  1125.         if (err != noErr) {        /* error occured? */
  1126.             zoutcnt = 0;
  1127.             zoutptr = zoutbuffer;
  1128.             sstate = 'a';        /* yes, cancel protocol */
  1129.             return (ioutil (err) ? 0 : -1); /* else return code */
  1130.         }
  1131.         
  1132.         fp[ZOFILE].fstatus &= ~FS_DATA;
  1133.         fp[ZOFILE].fstatus |= FS_RSRC;
  1134.         
  1135.         /*
  1136.          * tmpcnt is now the amount of extra buffer characters we
  1137.          * need to see in order to fill out this 128 byte "block".
  1138.          */
  1139.         tmpcnt = ((zcnt_written + 127) & ~127) - zcnt_written;
  1140.         if (wrcnt < tmpcnt) {
  1141.             /* mark more padding still needed */
  1142.             zcnt_written = -tmpcnt + wrcnt;
  1143.             zoutcnt = 0;
  1144.             zoutptr = zoutbuffer;
  1145.             return (0);        /* we are done this time */
  1146.         }
  1147.             
  1148.         /* all the padding is here -- skip over it */
  1149.         wrcnt -= tmpcnt;
  1150.         outp += tmpcnt;
  1151.         zcnt_written = 0;    /* reset for RSRC fork */
  1152.         /* fall through to RSRC fork if(), below... */
  1153.         }
  1154.     }
  1155.     
  1156.     /*
  1157.      * Also can't be "else if" here, because above if just might
  1158.      * feed this if too.
  1159.      */
  1160.     if (fp[ZOFILE].fstatus & FS_RSRC) {    /* if doing data fork */
  1161.         if (zcnt_written < 0) {    /* if we need to skip more padding */
  1162.             outp += -zcnt_written;
  1163.         wrcnt -= -zcnt_written;
  1164.         zcnt_written = 0;
  1165.         }
  1166.         if (zcnt_written + wrcnt >= filargs.rsrcsiz) {
  1167.         tmpcnt = wrcnt;        /* save old amount of data */
  1168.  
  1169.         /* figure how how much we really should write */
  1170.         wrcnt = filargs.rsrcsiz - zcnt_written;
  1171.         err = FSWrite (fp[ZOFILE].frefnum, &wrcnt, outp);
  1172.         zcnt_written += wrcnt;
  1173.         outp += wrcnt;
  1174.         
  1175.         wrcnt = tmpcnt - wrcnt;    /* adjust to reflect the write */
  1176.         
  1177.         /* close rsrc fork, set flags to toss output */
  1178.         if (err == noErr)
  1179.             err = FSClose (fp[ZOFILE].frefnum);
  1180.         if (err == noErr)    /* and if that worked */
  1181.             err = FlushVol (NILPTR,    /* flush  OS buffers */
  1182.                 filargs.filvol);
  1183.         if (err != noErr) {        /* error occured? */
  1184.             zoutcnt = 0;
  1185.             zoutptr = zoutbuffer;
  1186.             sstate = 'a';        /* yes, abort protocol */
  1187.             return (ioutil (err) ? 0 : -1);    /* else return code */
  1188.         }
  1189.         
  1190.         /* say this file is no longer open */
  1191.         fp[ZOFILE].fstatus &= ~(FS_OPEN | FS_DATA | FS_RSRC);
  1192.         
  1193.         zcnt_written += wrcnt;    /* we keep track of leftovers */
  1194.  
  1195.         zoutcnt = 0;
  1196.         zoutptr = zoutbuffer;
  1197.         return (0);        /* we are done this time */
  1198.         }
  1199.     }
  1200.     }
  1201.   norm_file:
  1202.     debug(F101,"  zoutdump: normal file, writing","",wrcnt);
  1203.  
  1204.     err = FSWrite (fp[ZOFILE].frefnum, &wrcnt, outp);
  1205.     debug(F101,"  zoutdump: FSWrite returned","",err);
  1206.     debug(F101,"  zoutdump: wrote","",wrcnt);
  1207.     zcnt_written += wrcnt;
  1208.     zoutcnt = 0;
  1209.     zoutptr = zoutbuffer;
  1210.     if (err != noErr) {        /* error occured? */
  1211.     sstate = 'a';        /* yes, abort protocol */
  1212.     return (ioutil (err) ? 0 : -1);    /* else return code */
  1213.     }
  1214.     flush_file_in_background(fp[ZOFILE].frefnum);
  1215.     return (0);        /* no problems */
  1216. }
  1217.  
  1218. /****************************************************************************/
  1219. /*  C H K F N  --  Internal function to verify file number is ok.
  1220.  *
  1221.  * Returns:
  1222.  *   TRUE  - file is open
  1223.  *  FALSE  - file is not open
  1224.  *
  1225.  * Issues an error message if the file number is not in range.
  1226.  *
  1227.  */
  1228. /****************************************************************************/
  1229. chkfn (n)
  1230. int n;
  1231. {
  1232.     if (n < ZNFILS)
  1233.     return ((fp[n].fstatus != 0));    /* if open, fstatus is nonzero */
  1234.  
  1235.     debug (F101, "chkfn: file number out of range", "", n);
  1236.     printerr ("chkfn - file number not in range: ", n);
  1237.     return (FALSE);        /* ugh */
  1238. }                /* chkfn */
  1239.  
  1240.  
  1241.  
  1242. /****************************************************************************/
  1243. /*  Z C H K I  --  Check if input file exists and is readable.
  1244.  *
  1245.  * Returns:
  1246.  *  >= 0 if the file can be read (returns the size).
  1247.  *    -1 if file doesn't exist or can't be accessed,
  1248.  *    -2 if file exists but is not readable (e.g. a directory file).
  1249.  *    -3 if file exists but protected against read access.
  1250.  */
  1251. /****************************************************************************/
  1252. long
  1253. zchki (name)
  1254. char *name;
  1255. {
  1256.     int err;
  1257.     ParamBlockRec info;
  1258.  
  1259.     if (strcmp (name, "stdin") == 0)    /* stdin is a pipe */
  1260.     return (PIPESIZE);    /* return size of buffer */
  1261.  
  1262.     c2pstr (name);        /* convert to a pascal string */
  1263.     info.fileParam.ioFVersNum = 0;    /* No version number */
  1264.     info.fileParam.ioFDirIndex = 0;    /* Use the file name */
  1265.     info.fileParam.ioNamePtr = name;    /* Point to the file name */
  1266.     info.fileParam.ioVRefNum = filargs.filvol;    /* Volume number */
  1267.     err = PBGetFInfo (&info, FALSE);    /* Get info on file */
  1268.     p2cstr (name);        /* put the name back */
  1269.  
  1270.     if (err == fnfErr)        /* file not found? */
  1271.     return (-1);        /* then that is what they want */
  1272.  
  1273.     if (err != noErr) {        /* any other error? */
  1274.     printerr ("zchki failed: ", err);    /* tell me about it */
  1275.     return (-1);
  1276.     }
  1277.  
  1278.     /* if we are doing MacBinary format transfer */
  1279.     if ((filargs.filflg & (FIL_RSRC|FIL_DATA)) == (FIL_RSRC|FIL_DATA)) {
  1280.     /*
  1281.      * MacBinary size is:
  1282.      *   128 byte header
  1283.      * + data fork, rounded up to the next 128 boundry
  1284.      * + resource fork, rounded up to the next 128 boundry
  1285.      */
  1286.     iflen = ((info.fileParam.ioFlLgLen + 127) & ~127)
  1287.          + ((info.fileParam.ioFlRLgLen + 127) & ~127)
  1288.          + 128;
  1289.     } else {
  1290.     /* normal (non-MacBinary) file */
  1291.     iflen = (filargs.filflg & FIL_RSRC) ?    /* if thinking about RSRC */
  1292.         info.fileParam.ioFlRLgLen :    /* return that size, */
  1293.         info.fileParam.ioFlLgLen;        /* else DATA */
  1294.     }
  1295.     
  1296.     return (iflen);        /* did ok */
  1297. }                /* zchki */
  1298.  
  1299.  
  1300.  
  1301. /****************************************************************************/
  1302. /*  Z C H K O  --  Check if output file can be created.
  1303.  *
  1304.  * Returns
  1305.  *  0: Write OK
  1306.  * -1: write permission for the file should be denied.
  1307.  */
  1308. /****************************************************************************/
  1309. zchko (name)
  1310. char *name;        /* unused in this */
  1311. {
  1312.     Str255 volname;
  1313.     ParamBlockRec info;
  1314.  
  1315.     info.volumeParam.ioVolIndex = 0;    /* Use the vol ref num only */
  1316.     info.volumeParam.ioNamePtr = &volname; /* Pointer to the volume name */
  1317.     info.volumeParam.ioVRefNum = filargs.filvol; /* Volume reference number */
  1318.     if (!ioutil (PBGetVInfo (&info, 0))) /* Get info on vol, synchronously */
  1319.     return (-1);            /* failed... */
  1320.  
  1321.     if ((info.volumeParam.ioVAtrb & 0x8000) != 0) /* Write locked? */
  1322.     return (-1);        /* yes... */
  1323.  
  1324.     return (0);            /* else success */
  1325. }                /* zchko */
  1326.  
  1327.  
  1328.  
  1329. /****************************************************************************/
  1330. /*  Z D E L E T  --  Delete the named file and return TRUE if successful */
  1331. /****************************************************************************/
  1332. int
  1333. zdelet (name) char *name; {
  1334.     int err;
  1335.     err = remove(name);
  1336.     debug(F101,"zdelet","",err);
  1337.     return(err == 0 ? 0 : -1);
  1338. }
  1339.  
  1340.  
  1341.  
  1342. /****************************************************************************/
  1343. /*  Z R T O L  --  Convert remote filename into local form.
  1344.  *
  1345.  * Check here to see if this should go into the resource fork (.rsrc)
  1346.  * or into the data fork (.data).
  1347.  *
  1348.  */
  1349. /****************************************************************************/
  1350. VOID zrtol (name, name2)
  1351. char *name, *name2;
  1352. {
  1353.  
  1354.     strcpy (name2, name);    /* copy name to destination */
  1355.  
  1356.     if (filargs.filflg & (FIL_DODLG))    /* selected by user? */
  1357.     return;            /* won't be called but... */
  1358.  
  1359.     filargs.filflg &= ~(FIL_RBDT);    /* clear out flags */
  1360.     filargs.filflg |= sfprtol (name2);    /* convert name2 and set flags */
  1361.     binary = (filargs.filflg & FIL_BINA);    /* selected binary mode? */
  1362.     return;
  1363. }                /* zrtol */
  1364.  
  1365. /****************************************************************************/
  1366. /*  Z S T R I P  --  Strip device & directory name from file specification */
  1367. /****************************************************************************/
  1368.  
  1369. /*  Strip pathname from filename "name", return pointer to result in name2 */
  1370.  
  1371. static char work[100];    /* buffer for use by zstrip */
  1372.  
  1373. VOID
  1374. zstrip(name,name2) char *name, **name2; {
  1375.     char *cp, *pp;
  1376.     debug(F110,"zstrip before",name,0);
  1377.     pp = work;
  1378.     for (cp = name; *cp != '\0'; cp++) {
  1379.         if (*cp == ':')
  1380.       pp = work;
  1381.     else
  1382.       *pp++ = *cp;
  1383.     }
  1384.     *pp = '\0';                /* Terminate the string */
  1385.     *name2 = work;
  1386.     debug(F110,"zstrip after",*name2,0);
  1387. }
  1388.  
  1389. /****************************************************************************/
  1390. /*  Z L T O R  --  Convert filename from local format to common form. */
  1391. /****************************************************************************/
  1392. void zltor(name, name2) char *name, *name2; {
  1393.     int dc = 0;                /* Dot counter */
  1394.     char c;                /* For each character from name */
  1395.     char *pp;                /* Pointer to work buffer */
  1396.  
  1397.     pp = work;                /* Point to start of work buffer */
  1398.  
  1399.     while ((c = *name++) != '\0') {    /* Go thru original name */
  1400.     if (c == ' ')            /* Change space to underscore */
  1401.           *pp++ = '_';
  1402.     else if (c == ':')        /* Colon is the directory seperator */
  1403.           pp = work;            /* Strip pathname */
  1404.     else if ((c == '.') && (++dc > 1))
  1405.       *pp++ = 'X';            /* Just 1 dot allowed */
  1406.     else                /* Convert letters to uppercase */
  1407.       *pp++ = (islower(c)) ? toupper(c) : c;
  1408.     }
  1409.     *pp =  '\0';            /* Deposit final null */
  1410.     pp = work;                /* Back to beginning of work buffer */
  1411.     if (*pp == '.')            /* If it starts with a dot, */
  1412.       *name2++ = 'X';            /* insert an X. */
  1413.     strcpy(name2,work);            /* Copy result to destination. */
  1414.     if (strlen(name2) == 0)        /* Make sure something is there. */
  1415.       strcpy(name2,"X");
  1416.     debug(F110," name2",name2,0);    /* (debug) */
  1417.     return;
  1418. }                    /* zltor */
  1419.  
  1420. static char *mgbufp = NULL;
  1421. extern char *malloc();
  1422.  
  1423. #ifndef NOMSEND                /* Multiple SEND */
  1424. #define MSENDMAX 100
  1425. char *msfiles[MSENDMAX];
  1426. #endif
  1427.  
  1428. /*  F N P A R S E  --  */
  1429.  
  1430. /*
  1431.   Argument is a character string containing one or more filespecs.
  1432.   This function breaks the string apart into an array of pointers, one
  1433.   to each filespec, and returns the number of filespecs.  Used by server
  1434.   when it receives a GET command to allow it to process multiple file
  1435.   specifications in one transaction.  Sets cmlist to point to a list of
  1436.   file pointers, exactly as if they were command line arguments.
  1437.  
  1438.   This version of fnparse treats spaces as filename separators.  If your
  1439.   operating system allows spaces in filenames, you'll need a different 
  1440.   separator.  
  1441.  
  1442.   This version of fnparse mallocs a string buffer to contain the names.  It
  1443.   cannot assume that the string that is pointed to by the argument is safe.
  1444. */
  1445. #ifdef MAC                /* Filename separator */
  1446. #define FNSEP ','
  1447. #else
  1448. #define FNSEP SP
  1449. #endif
  1450. fnparse(string) char *string; {
  1451.     char *p, *s;
  1452.     int r = 0;                /* Return code */
  1453.     extern char **cmlist;
  1454.     
  1455.     if (mgbufp) free(mgbufp);        /* Free this from last time. */
  1456.     mgbufp = malloc(strlen(string)+2);
  1457.     if (!mgbufp) {
  1458.     debug(F100,"fnparse malloc error","",0);
  1459.     return(0);
  1460.     }    
  1461.     strcpy(mgbufp,string);        /* Make a safe copy */
  1462.     p = s = mgbufp;            /* Point to the copy */
  1463.     r = 0;                /* Initialize our return code */
  1464.     while (*p == SP) p++,s++;        /* Skip leading spaces */
  1465.     while (1) {                /* Loop through rest of string */
  1466.     if (*s == FNSEP || *s == NUL) {    /* Look for separator or terminator */
  1467.         msfiles[r] = p;        /* Add this filename to the list */
  1468.         debug(F111,"fnparse",msfiles[r],r);
  1469.         r++;            /* Count it */
  1470.         if (*s == NUL) break;    /* End of string? */
  1471.         *s++ = NUL;            /* No, turn space to NUL */
  1472.         while (*s == SP) s++;    /* Skip repeated spaces */
  1473.         p = s;            /* Start of next name */
  1474.         continue;
  1475.     }
  1476.     s++;                /* Otherwise keep scanning */
  1477.     }
  1478.     debug(F101,"fnparse r","",r);
  1479.     cmlist = msfiles;
  1480.     return(r);
  1481. }
  1482.  
  1483.  
  1484. /****************************************************************************/
  1485. /*  Z C H K S P A  --  Check if there is enough space to store the file  */
  1486. /****************************************************************************/
  1487.  
  1488. /*
  1489.  Call with file specification f, size n in bytes.
  1490.  Returns -1 on error, 0 if not enough space, 1 if enough space.
  1491. */
  1492. zchkspa(f,n) char *f; long n; {        /* $$$ Just dummy for now. */
  1493.     return(1);                /* Always say OK. */
  1494. }
  1495.  
  1496.  
  1497. /****************************************************************************/
  1498. /*  Z R E N A M E  --  Rename a file  */
  1499. /****************************************************************************/
  1500.  
  1501. /*  Call with old and new names */
  1502. /*  Returns 0 on success, -1 on failure. */
  1503.  
  1504. int
  1505. zrename(old,new) char *old, *new; {
  1506.     int err;
  1507.     err = rename(old,new);
  1508.     debug(F101,"zrenam","",err);
  1509.     return(err == 0 ? 0 : -1);
  1510. }
  1511.  
  1512.  
  1513. /****************************************************************************/
  1514. /*  Z C H D I R  --  Change directory or volumes */
  1515. /****************************************************************************/
  1516. int
  1517. zchdir (dirnam) char *dirnam; {
  1518.     int err;
  1519.     int volnum;
  1520.     WDPBRec vinfo;
  1521.     short *FSFCBLen = (short *)0x3F6;
  1522.  
  1523.     if (*FSFCBLen < 0) {    /* if no HFS ROM's */
  1524.     err = SetVol (c2p_tmp(dirnam), 0);
  1525.     volnum = 0;
  1526.     } else {            /* use HFS calls */
  1527.     c2pstr (dirnam);
  1528.     vinfo.ioVRefNum = 0;    /* open a workimg directory */
  1529.     vinfo.ioWDDirID = 0;
  1530.     vinfo.ioWDProcID = 'ERIK';
  1531.     vinfo.ioNamePtr = dirnam;
  1532.     err = PBOpenWD (&vinfo, FALSE);
  1533.     p2cstr (dirnam);
  1534.     if (err != noErr)
  1535.         return (FALSE);
  1536.  
  1537.     err = SetVol (NIL, vinfo.ioVRefNum);
  1538.     volnum = vinfo.ioVRefNum;
  1539.     }
  1540. #ifdef COMMENT
  1541. /*
  1542.   Don't write to screen!
  1543. */
  1544.     if (err == noErr) {            /* set default volume */
  1545.     screen (SCR_TN, 0, 0l, dirnam);
  1546.     filargs.filvol = volnum;    /* make default */
  1547.     } else
  1548.     screen (SCR_TN, 0, 0l, "Can't set directory");
  1549. #else
  1550.     if (err == noErr) {            /* set default volume */
  1551.     filargs.filvol = volnum;    /* make default */
  1552.     }
  1553. #endif /* COMMENT */
  1554.     return (err == noErr);    /* return ok or fail */
  1555. }                /* zchdir */
  1556.  
  1557. /****************************************************************************/
  1558. /*  Z H O M E  --  Return pointer to user's home directory  */
  1559. /****************************************************************************/
  1560. /*
  1561.   This one should return the name of the boot volume.
  1562. */
  1563. char *
  1564. zhome() {
  1565.     return("(directory unknown)");    /* PWP: for now */
  1566. }
  1567.  
  1568. /****************************************************************************/
  1569. /*  Z G T D I R  --  Return pointer to user's current directory  */
  1570. /****************************************************************************/
  1571. /*
  1572.   This one should
  1573. */
  1574. char *
  1575. zgtdir() {
  1576.     return ("(directory unknown)");    /* PWP: for now */
  1577. }
  1578.  
  1579. /****************************************************************************/
  1580. /* initialize the fields of a pipe */
  1581. /****************************************************************************/
  1582. zinitpipe (pipe, refillproc)
  1583. MACPIPE *pipe;
  1584. ProcPtr refillproc;
  1585. {
  1586.     pipe->refill = refillproc;
  1587.     pipe->currptr = pipe->pipebuf;
  1588.     pipe->charsleft = 0;
  1589.     *(pipe->currptr) = '\0';
  1590. }                /* zinitpipe */
  1591.  
  1592.  
  1593.  
  1594. /****************************************************************************/
  1595. /* fill the pipe; last is TRUE if it is the */
  1596. /* last time the pipe has to be filled  */
  1597. /****************************************************************************/
  1598. zfillpipe (pipe, str, last)
  1599. MACPIPE *pipe;
  1600. char *str;
  1601. Boolean last;
  1602. {
  1603.     int len;
  1604.  
  1605.     len = strlen (str);
  1606.     if (last)
  1607.     len++;
  1608.  
  1609.     if (len > PIPESIZE) {
  1610.     len = PIPESIZE;
  1611.     if (last)
  1612.         str[PIPESIZE - 1] = '\0';    /* make sure we keep the eop
  1613.                      * character */
  1614.     printerr ("pipe overflow! characters may be lost", 0);
  1615.     }
  1616.     memcpy (pipe->pipebuf, str, len);
  1617.     pipe->charsleft = len;
  1618. }                /* zfillpipe */
  1619.  
  1620.  
  1621.  
  1622. /****************************************************************************/
  1623. /* sprintf uses 12 kByte. This is the reason to use a simpler formatter here */
  1624. /* formatnum returns a right adjusted numberstring padded with fillc */
  1625. /* Numbers which do not fit into width are truncated on the left. */
  1626. /* Make sure str is at least 'width+1' bytes wide */
  1627. /****************************************************************************/
  1628. formatnum (num, fillc, width, str)
  1629. char *str;
  1630. long num;
  1631. char fillc;
  1632. int width;
  1633. {
  1634.     int i;
  1635.     char numstr[12];        /* -2147483647 is the longest string */
  1636.     /* that can be returned from NumToString */
  1637.  
  1638.     NumToString (num, numstr);
  1639.     p2cstr(numstr);
  1640.     i = strlen (numstr);
  1641.  
  1642.     while ((i >= 0) && (width >= 0))
  1643.     str[width--] = numstr[i--];
  1644.  
  1645.     while (width >= 0)
  1646.     str[width--] = fillc;
  1647. }                /* formatnum */
  1648.  
  1649.  
  1650.  
  1651. MACPIPE cmdpipe;
  1652.  
  1653. int volindex;
  1654. char spaceheader[60] = "\
  1655. Free      Name\n\
  1656. --------- --------------------\n";
  1657.  
  1658. /****************************************************************************/
  1659. /* loop through all available volumes and display the space left */
  1660. /****************************************************************************/
  1661. zlspace ()
  1662. {
  1663.     int err;
  1664.     Str255 name;
  1665.     long free;
  1666.     char outstr[60];
  1667.     ParamBlockRec vinfo;
  1668.  
  1669.     name[0] = 0;        /* name.length = 0; */
  1670.     vinfo.volumeParam.ioVolIndex = volindex;
  1671.     vinfo.volumeParam.ioNamePtr = &name;
  1672.     err = PBGetVInfo (&vinfo, FALSE);
  1673.  
  1674.     if (err == noErr) {
  1675.     free = vinfo.volumeParam.ioVFrBlk * vinfo.volumeParam.ioVAlBlkSiz;
  1676.     formatnum (free, ' ', 9, outstr);
  1677.     strcat (outstr, " ");
  1678.     p2cstr (&name);
  1679.     strcat (outstr, &name);
  1680.     strcat (outstr, "\n");
  1681.     zfillpipe (&cmdpipe, outstr, FALSE);
  1682.     volindex++;
  1683.     } else
  1684.     zfillpipe (&cmdpipe, "", TRUE);
  1685.  
  1686. }                /* zlspace */
  1687.  
  1688.  
  1689.  
  1690. int fileindex;
  1691. char dirheader[100] = "\
  1692. Size    Type Crea Last Modification Name\n\
  1693. ------- ---- ---- ----------------- --------------------\n";
  1694.  
  1695. /****************************************************************************/
  1696. /* loop through all the files on the current volume / directory */
  1697. /****************************************************************************/
  1698. zldir ()
  1699. {
  1700.     int err;
  1701.     CInfoPBRec info;
  1702.     WDPBRec vinfo;
  1703.  
  1704.     Str255 name;
  1705.     DateTimeRec dtrec;
  1706.  
  1707.     char outstr[60];
  1708.     char type[10];
  1709.     char tmpstr[11];
  1710.     char datestr[11];
  1711.     char hourstr[3];
  1712.     char minutestr[3];
  1713.  
  1714.     unsigned long secs;
  1715.     long size;
  1716.  
  1717.     short *FSFCBLen = (short *) 0x3F6;
  1718.  
  1719.     if (*FSFCBLen < 0) {
  1720.     /* errpkt ("Sorry, the server uses 64 kByte ROM's"); */
  1721.     errpkt ("Sorry, the server is not running on an HFS disk"); /* $$$ */
  1722.     zfillpipe (&cmdpipe, "", TRUE);
  1723.     return;
  1724.     }
  1725.     PBHGetVol (&vinfo, FALSE);
  1726.  
  1727.     /* loop through all the files starting at the first one */
  1728.     name[0] = 0;        /* name.length = 0; */
  1729.     info.hfileInfo.ioFDirIndex = fileindex;    /* Get next file name */
  1730.     info.hfileInfo.ioNamePtr = &name;    /* Point to the empty file name */
  1731.     info.hfileInfo.ioVRefNum = vinfo.ioWDVRefNum;    /* Directory / Volume
  1732.                              * number */
  1733.     info.hfileInfo.ioDirID = vinfo.ioWDDirID;    /* Directory / Volume number */
  1734.     err = PBGetCatInfo (&info, FALSE);    /* Get info on file */
  1735.  
  1736.     if (err == noErr) {
  1737.     if (info.hfileInfo.ioFlAttrib & ioDirMask) {    /* a directory if it's
  1738.                              * true */
  1739.         secs = info.dirInfo.ioDrMdDat;
  1740.         strcpy (type, "#########");
  1741.         strcpy (outstr, "       ");
  1742.     } else {        /* a file otherwise */
  1743.         secs = info.hfileInfo.ioFlMdDat;
  1744.         size = info.hfileInfo.ioFlLgLen + info.hfileInfo.ioFlRLgLen;
  1745.         strcpy (type, "         ");
  1746.         memcpy (type, &info.hfileInfo.ioFlFndrInfo.fdType, 4);
  1747.         memcpy (type + 5, &info.hfileInfo.ioFlFndrInfo.fdCreator, 4);
  1748.         formatnum (size, ' ', 7, outstr);
  1749.     }
  1750.     IUDateString (secs, shortDate, tmpstr);
  1751.     p2cstr(tmpstr);
  1752.     strcpy (datestr, "   ");
  1753.     datestr[10 - strlen (tmpstr)] = '\0';
  1754.     strcat (datestr, tmpstr);
  1755.  
  1756.     Secs2Date (secs, &dtrec);
  1757.     formatnum (dtrec.hour, ' ', 2, hourstr);
  1758.     formatnum (dtrec.minute, '0', 2, minutestr);
  1759.  
  1760.     p2cstr (&name);
  1761.  
  1762.     strcat (outstr, " ");
  1763.     strcat (outstr, type);
  1764.     strcat (outstr, " ");
  1765.     strcat (outstr, datestr);
  1766.     strcat (outstr, " ");
  1767.     strcat (outstr, hourstr);
  1768.     strcat (outstr, ":");
  1769.     strcat (outstr, minutestr);
  1770.     strcat (outstr, "  ");
  1771.     strcat (outstr, &name);
  1772.     strcat (outstr, "\n");
  1773.  
  1774.     zfillpipe (&cmdpipe, outstr, FALSE);
  1775.     fileindex++;
  1776.     } else
  1777.     zfillpipe (&cmdpipe, "", TRUE);
  1778.  
  1779. }                /* zldir */
  1780.  
  1781.  
  1782.  
  1783. #define CMD_RSRC    1
  1784. #define CMD_DATA    2
  1785. #define CMD_TEXT    3
  1786. #define CMD_BINA    4
  1787. #define CMD_DIR        5
  1788. #define CMD_DEL        6
  1789. #define CMD_SPC        7
  1790. #define CMD_UNK 255
  1791.  
  1792. char *cmdtab[] = {
  1793.     "fork rsrc",
  1794.     "fork data",
  1795.     "mode binary",
  1796.     "mode text",
  1797.     DIRCMDSTR,
  1798.     DELCMDSTR,
  1799.     SPCCMDSTR
  1800. };
  1801.  
  1802. int toktab[] = {
  1803.     CMD_RSRC,
  1804.     CMD_DATA,
  1805.     CMD_BINA,
  1806.     CMD_TEXT,
  1807.     CMD_DIR,
  1808.     CMD_DEL,
  1809.     CMD_SPC
  1810. };
  1811.  
  1812. #define NTOKS (sizeof (toktab)/sizeof(int))
  1813.  
  1814. /****************************************************************************/
  1815. /*  Z X C M D -- Run a system command so its output can be read like a file.
  1816.  *
  1817.  * Used on the MAC to implement MAC settings commands -- commands from a
  1818.  * remote system when in server mode that change internal variables.
  1819.  *
  1820.  */
  1821. /****************************************************************************/
  1822. int
  1823. zmxcmd (comand)
  1824. char *comand;
  1825. {
  1826.     int sc;
  1827.     char theStr[120];
  1828.     int retCd;
  1829.  
  1830.     fp[ZIFILE].fstatus = FS_PIPE;    /* set input from pipe */
  1831.     fp[ZIFILE].fpipe = &cmdpipe;/* init pointer to command pipe */
  1832.  
  1833.     switch (sc = getcmd (comand)) {
  1834.       case CMD_RSRC:
  1835.       case CMD_DATA:
  1836.     zinitpipe (&cmdpipe, NILPROC);
  1837.     zfillpipe (&cmdpipe, "Default Fork set OK\n", TRUE);
  1838.     filargs.filflg &= ~(FIL_RSRC | FIL_DATA);    /* turn off  */
  1839.     filargs.filflg |= (sc == CMD_RSRC) ? FIL_RSRC : FIL_DATA;
  1840.     return (TRUE);        /* ok */
  1841.  
  1842.       case CMD_TEXT:
  1843.       case CMD_BINA:
  1844.     zinitpipe (&cmdpipe, NILPROC);
  1845.     zfillpipe (&cmdpipe, "Default Mode set OK\n", TRUE);
  1846.     filargs.filflg &= ~(FIL_TEXT | FIL_BINA);
  1847.     filargs.filflg |= (sc == CMD_BINA) ? FIL_BINA : FIL_TEXT;
  1848.     return (TRUE);        /* ok */
  1849.  
  1850.       case CMD_DIR:
  1851.     zinitpipe (&cmdpipe, zldir);
  1852.     zfillpipe (&cmdpipe, dirheader, FALSE);
  1853.     fileindex = 1;        /* start at the first file on */
  1854.     /* the current volume / directory */
  1855.     return (TRUE);        /* always ok */
  1856.  
  1857.       case CMD_DEL:
  1858.     strcpy (theStr, comand + strlen (DELCMDSTR));    /* the filename
  1859.                              * immediately  */
  1860.     retCd = zdelet (theStr);/* follows the command name */
  1861.     if (retCd) {
  1862.         zinitpipe (&cmdpipe, NILPROC);
  1863.         strcat (theStr, " deleted.");
  1864.         zfillpipe (&cmdpipe, theStr, true);
  1865.     }
  1866.     return (retCd);
  1867.  
  1868.       case CMD_SPC:
  1869.     zinitpipe (&cmdpipe, zlspace);    /* init pipe for space listing */
  1870.     zfillpipe (&cmdpipe, spaceheader, FALSE);    /* copy the header to
  1871.                              * the pipe */
  1872.     volindex = 1;        /* start with the first volume */
  1873.     return (TRUE);        /* always ok */
  1874.  
  1875.       default:
  1876.     return (FALSE);        /* fail, unknown */
  1877.     }
  1878. }                /* zxcmd */
  1879.  
  1880.  
  1881. /*
  1882.  * zxcmd
  1883.  * Temporary so we can link correctly.
  1884.  */
  1885. zxcmd(filnum,comand) 
  1886.     int filnum; 
  1887.     char *comand; 
  1888. {
  1889.     printerr("MAC zxcmd called", 0);
  1890.     return 0;
  1891. }
  1892.  
  1893.  
  1894. /****************************************************************************/
  1895. /****************************************************************************/
  1896. getcmd (cmd)
  1897. char *cmd;
  1898. {
  1899.     int k;
  1900.  
  1901.     for (k = 0; k < NTOKS; k++)
  1902.     if (strncmp (cmdtab[k], cmd, strlen (cmdtab[k])) == 0)
  1903.         return (toktab[k]);    /* and return ID */
  1904.     return (CMD_UNK);        /* else unknown */
  1905.  
  1906. }                /* getcmd */
  1907.  
  1908.  
  1909.  
  1910. /****************************************************************************/
  1911. /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
  1912. /****************************************************************************/
  1913. zclosf ()
  1914. {
  1915.     return;
  1916. }                /* zclosf */
  1917.  
  1918.  
  1919.  
  1920. int zindex;
  1921. int zfiles;
  1922. char *zname;
  1923. static char znm_storage[64];
  1924.  
  1925. /****************************************************************************/
  1926. /*  Z X P A N D  --  Expand a wildcard string into an array of strings
  1927.  *
  1928.  * Returns the number of files that match fn, with data structures set up
  1929.  * so that first file (if any) will be returned by the next znext() call.
  1930.  */
  1931. /****************************************************************************/
  1932. zxpand (fn)
  1933. char *fn;
  1934. {
  1935.     int err;
  1936.     ParamBlockRec info;
  1937.  
  1938.     zfiles = 1;
  1939.  
  1940.     debug(F110,"  zxpand fn",fn, 0);
  1941.  
  1942.     if ((filargs.filflg & FIL_ALLFL) ||    /* all files check box on or */
  1943.     (strcmp (fn, ":") == 0)) {    /* server 'get' with filname = ':' */
  1944.  
  1945.     /* the ioVNmFls field of the VolumeParam returns the number of files */
  1946.  
  1947.     /*
  1948.      * !and! directories after PBGetInfo. This is why we have to count
  1949.      * here.
  1950.      */
  1951.  
  1952.     info.fileParam.ioFVersNum = 0;    /* No version number */
  1953.     info.fileParam.ioNamePtr = NIL;    /* Point to the file name */
  1954.     info.fileParam.ioVRefNum = filargs.filvol;    /* Volume number */
  1955.     do {
  1956.         info.fileParam.ioFDirIndex = zfiles; /* Get next file name */
  1957.         err = PBGetFInfo (&info, FALSE);    /* Get info on file */
  1958.         zfiles++;
  1959.     } while (err == noErr);
  1960.     zname = NIL;        /* no specific file */
  1961.     zfiles -= 2;        /* we counted 2 too high */
  1962.  
  1963.     } else {
  1964.     
  1965.         strncpy(znm_storage, fn, 63);    /* copy fn to local storage */
  1966.     znm_storage[63] = '\0';        /* string paranoia */
  1967.     zname = znm_storage;        /* keep a pointer to that name */
  1968.     }
  1969.     
  1970.     zindex = 0;            /* init the files sent counter */
  1971.     return (zfiles);
  1972. }                /* zxpand */
  1973.  
  1974.  
  1975.  
  1976. /****************************************************************************/
  1977. /*  Z N E X T  --  Get name of next file from list created by zxpand().
  1978.  *
  1979.  * Returns >0 if there's another file, with its name copied into the
  1980.  * arg string, or 0 if no more files in list.
  1981.  */
  1982. /****************************************************************************/
  1983. znext (fn)
  1984. char *fn;
  1985. {
  1986.     int err;
  1987.     Str255 name;
  1988.     ParamBlockRec info;
  1989.  
  1990.     zindex++;            /* next file */
  1991.  
  1992.     if (zindex > zfiles)
  1993.     return (0);        /* no more files */
  1994.  
  1995.     if (zname != NIL)
  1996.     strcpy (fn, zname);    /* Get the file's name */
  1997.     else {
  1998.     info.fileParam.ioFVersNum = 0;    /* No version number */
  1999.     info.fileParam.ioFDirIndex = zindex;    /* Get next file name */
  2000.     info.fileParam.ioNamePtr = &name;    /* Point to the file name */
  2001.     /* VolRefNum of the selected folder */
  2002.     info.fileParam.ioVRefNum = filargs.filvol; 
  2003.     err = PBGetFInfo (&info, FALSE); /* Get info on file */
  2004.     if (err == noErr) {
  2005.         p2cstr (&name);
  2006.         strcpy (fn, &name);    /* Return the file's name */
  2007.         *filargs.filrem = '\0';    /* reset remote name for folder
  2008.                          * transfer */
  2009.     } else {
  2010.         printerr ("Error on reading next file name: ", err);
  2011.         return (0);
  2012.     }
  2013.     }
  2014.     return (1);            /* fn contains the next file */
  2015. }                /* znext */
  2016.  
  2017.  
  2018.  
  2019. /****************************************************************************/
  2020. /*  Z N E W N  --  Make a new name for the given file  */
  2021. /****************************************************************************/
  2022. VOID
  2023. znewn (fn, s) char *fn, **s; {
  2024.     char *extp, *tmpnam(char *);
  2025.     int ver;
  2026.     static char buf[70];        /* Enough for a Mac filename */
  2027.     char *p;
  2028.  
  2029.     p = buf;
  2030.     strncpy(p, fn, 59);         /* copy in the name, no long names! */
  2031.     extp = p + strlen(p);    /* find position of extension */
  2032.     *extp++ = '.';        /* add in the dot now */
  2033.  
  2034.     for (ver = 0; ver < 99; ver++) {    /* I'll try this many names */
  2035.     NumToString ((long) ver, extp);    /* add in the number */
  2036.     p2cstr(extp);
  2037.     if (zchki(p) == -1) {    /* is this file known? */
  2038.         *s = buf;        /* no, we can use this name. */
  2039.         return;
  2040.     }
  2041.     }
  2042.     p = buf;            /* Failed, use tmpnam(). */
  2043.     *s = tmpnam(p);
  2044.     return;
  2045. }                /* znewn */
  2046.  
  2047. /*  I S W I L D */
  2048. /*
  2049.  * return true (1) if the file spec contains any Kermit wild cards
  2050.  */
  2051.  
  2052. iswild(filespec) char *filespec; {
  2053.     return (0);            /* MacKermit doesn't do wild cards yet */
  2054. }
  2055.  
  2056.  
  2057. /*  Z S A T T R */
  2058. /*
  2059.  Fills in a Kermit file attribute structure for the file which is to be sent.
  2060.  Returns 0 on success with the structure filled in, or -1 on failure.
  2061.  If any string member is null, then it should be ignored.
  2062.  If any numeric member is -1, then it should be ignored.
  2063. */
  2064. zsattr(xx) struct zattr *xx; {
  2065.     long k;
  2066.  
  2067.     k = iflen % 1024L;                  /* File length in K */
  2068.     if (k != 0L) k = 1L;
  2069.     xx->lengthk = (iflen / 1024L) + k;
  2070.     xx->type.len = 0;                   /* File type can't be filled in here */
  2071.     xx->type.val = "";
  2072.     xx->date.len = 0;                   /* File creation date */
  2073.     xx->date.val = "";
  2074.     xx->creator.len = 0;                /* File creator */
  2075.     xx->creator.val = "";
  2076.     xx->account.len = 0;                /* File account */
  2077.     xx->account.val = "";
  2078.     xx->area.len = 0;                   /* File area */
  2079.     xx->area.val = "";
  2080.     xx->passwd.len = 0;                 /* Area password */
  2081.     xx->passwd.val = "";
  2082.     xx->blksize = -1L;                  /* File blocksize */
  2083.     xx->access.len = 0;                 /* File access */
  2084.     xx->access.val = "";
  2085.     xx->encoding.len = 0;               /* Transfer syntax */
  2086.     xx->encoding.val = 0;
  2087.     xx->disp.len = 0;                   /* Disposition upon arrival */
  2088.     xx->disp.val = "";
  2089.     xx->lprotect.len = 0;               /* Local protection */
  2090.     xx->lprotect.val = "";
  2091.     xx->gprotect.len = 0;               /* Generic protection */
  2092.     xx->gprotect.val = "";
  2093.     xx->systemid.len = 2;               /* System ID */
  2094.     xx->systemid.val = "A3";        /* (A3: Apple Macintosh) */
  2095.     xx->recfm.len = 0;                  /* Record format */
  2096.     xx->recfm.val = "";
  2097.     xx->sysparam.len = 0;               /* System-dependent parameters */
  2098.     xx->sysparam.val = "";
  2099.     xx->length = iflen;                 /* Length */
  2100.     return(0);
  2101. }
  2102.  
  2103. /* Find initialization file. */
  2104.  
  2105. zkermini() {
  2106. /*  nothing yet...  this function added for benefit of VMS Kermit.  */
  2107.     return(0);
  2108. }
  2109.  
  2110. /****************************************************************************/
  2111. pascal void
  2112. reset ()
  2113. /****************************************************************************/
  2114. extern 0x4E70;
  2115.  
  2116. /****************************************************************************/
  2117. /* zkself() - Kill self (reboot).  On other machines does a logout.
  2118.  *              Flush volumes and reboot.  Called by remote BYE.
  2119.  *
  2120.  */
  2121. /****************************************************************************/
  2122. zkself ()
  2123. {
  2124.     DrvQEl *drvqe;
  2125.     Str255 vname;
  2126.     long vfreeb;
  2127.     short vrefnum;
  2128.     int err;
  2129.  
  2130.     /* handle on drive q */
  2131.     for (drvqe = (DrvQEl *) ((QHdr *) GetDrvQHdr ())->qHead;
  2132.      drvqe != NULL;        /* while still something */
  2133.      drvqe = (DrvQEl *) drvqe->qLink) { /* step to next for each drive */
  2134.     err = GetVInfo (drvqe->dQDrive, &vname, &vrefnum, &vfreeb);
  2135.     if (err == noErr)
  2136.         err = FlushVol (NILPTR, vrefnum);    /* flush the volume given
  2137.                          * refnum */
  2138.     else if (err != nsvErr)
  2139.         screen (SCR_TN,0,0l,"Remote cmd: GetVinfo returned unknown code");
  2140.     }
  2141.  
  2142.     doclean ();            /* clean up before leaving */
  2143.     
  2144.     doexit(GOOD_EXIT, -1);
  2145. }                /* zkself */
  2146.  
  2147. char optbuf[50];        /* used for MAIL and REMOTE PRINT options */
  2148.  
  2149. zmail(p,f) char *p; char *f; {        /* Send file f as mail to address p */
  2150.     screen (SCR_WM,0,0l,"There is no mail support in Mac Kermit.");
  2151. }
  2152.  
  2153. zprint(p,f) char *p; char *f; {        /* Print file f with options p */
  2154.     screen (SCR_WM,0,0l,"There is no printer support in Mac Kermit yet.");
  2155. }
  2156.  
  2157. struct {
  2158.     int errnum;
  2159.     char *errstr;
  2160. }   ioerrs[] = {
  2161.  
  2162.     {
  2163.     dirFulErr, "Directory is full"
  2164.     },
  2165.     {
  2166.     dskFulErr, "Disk is full"
  2167.     },
  2168.     {
  2169.     wPrErr, "Diskette is write protected"
  2170.     },
  2171.     {
  2172.     fLckdErr, "File is software locked"
  2173.     },
  2174.     {
  2175.     vLckdErr, "Volume is software locked"
  2176.     },
  2177.     {
  2178.     fBsyErr, "File is busy"
  2179.     },
  2180.     {
  2181.     opWrErr, "File is already open with write permission"
  2182.     },
  2183.     {
  2184.     fnfErr, "File does not exist"
  2185.     },
  2186.     {
  2187.     0, NILPTR
  2188.     }
  2189. };
  2190.  
  2191. /****************************************************************************/
  2192. /* ioutil - handle the result from an IO call, checking for an
  2193.  *            error return and displaying an appropriate error
  2194.  *            message.  Returns TRUE if no error occured, FALSE
  2195.  *            otherwise.
  2196.  */
  2197. /****************************************************************************/
  2198. int
  2199. ioutil (err)
  2200. int err;
  2201. {
  2202.     int e;
  2203.  
  2204.     if (err == noErr)
  2205.     return (TRUE);
  2206.  
  2207.     for (e = 0; ioerrs[e].errnum != 0 && ioerrs[e].errnum != err; e++);
  2208.  
  2209.     if (ioerrs[e].errstr == NILPTR)    /* anything there? */
  2210.     printerr ("Unknown IO error: ", err);
  2211.     else
  2212.     printerr (ioerrs[e].errstr, 0);
  2213.  
  2214.     return (FALSE);
  2215. }                /* ioutil */
  2216.  
  2217.  
  2218. /****************************************************************************
  2219.  * OpenRF_rdonly() -- An interface just like OpenRF, but open for read only.
  2220.  ****************************************************************************/
  2221. OSErr 
  2222. OpenRF_rdonly (char *fileName, short vRefNum, short *refNum)
  2223. {
  2224.     ParamBlockRec pb;
  2225.  
  2226.     if (!fileName)
  2227.     DebugStr("\pfileName == NULL");
  2228.     if (!refNum)
  2229.     DebugStr("\prefNum == NULL");
  2230.  
  2231.     pb.ioParam.ioCompletion = (ProcPtr) 0;
  2232.     pb.ioParam.ioNamePtr = fileName;
  2233.     pb.ioParam.ioVRefNum = vRefNum;
  2234.     pb.ioParam.ioVersNum = 0;
  2235.     pb.ioParam.ioPermssn = fsRdPerm;
  2236.     pb.ioParam.ioMisc = (Ptr) 0;
  2237.     PBOpenRF (&pb, 0);
  2238.     *refNum = pb.ioParam.ioRefNum;
  2239.     return pb.ioParam.ioResult;
  2240. }                /* OpenRF_rdonly */
  2241.  
  2242.  
  2243. /****************************************************************************
  2244.  * FSOpen_rdonly() -- An interface just like FSOpen, but open for read only.
  2245.  ****************************************************************************/
  2246. OSErr 
  2247. FSOpen_rdonly (char *fileName, short vRefNum, short *refNum)
  2248. {
  2249.     ParamBlockRec pb;
  2250.  
  2251.     if (!fileName)
  2252.     DebugStr("\pfileName == NULL");
  2253.     if (!refNum)
  2254.     DebugStr("\prefNum == NULL");
  2255.  
  2256.     pb.ioParam.ioCompletion = (ProcPtr) 0;
  2257.     pb.ioParam.ioNamePtr = fileName;
  2258.     pb.ioParam.ioVRefNum = vRefNum;
  2259.     pb.ioParam.ioVersNum = 0;
  2260.     pb.ioParam.ioPermssn = fsRdPerm;
  2261.     pb.ioParam.ioMisc = (Ptr) 0;
  2262.     PBOpen (&pb, 0);
  2263.     *refNum = pb.ioParam.ioRefNum;
  2264.     return pb.ioParam.ioResult;
  2265. }                /* FSOpen_rdonly */
  2266.  
  2267.  
  2268.  
  2269.  
  2270. extern short dfltVol;
  2271.  
  2272. short tlogfile;
  2273. char tlogname[] = "Kermit Transaction";
  2274.  
  2275. /****************************************************************************/
  2276. /****************************************************************************/
  2277. opentlog ()
  2278. {
  2279.     return (openlogfile("Transaction log name:", tlogname, &tlogfile, ZTFILE));
  2280. }
  2281.  
  2282. /****************************************************************************/
  2283. /****************************************************************************/
  2284. closetlog ()
  2285. {
  2286.     FSClose (tlogfile);
  2287.     FlushVol (NIL, dfltVol);
  2288. }                /* closetlog */
  2289.  
  2290.  
  2291. #ifdef COMMENT
  2292. /****************************************************************************/
  2293. /****************************************************************************/
  2294. tlog (f, s1, s2, n)
  2295. int f;        /* unused */
  2296. long n;
  2297. char *s1;
  2298. char *s2;
  2299. {
  2300.     char numstr[12];
  2301.     char outstr[256];
  2302.     long count;
  2303.  
  2304.     if (tralog) {
  2305.     strcpy (outstr, s1);
  2306.  
  2307.     if (strlen (s2)) {
  2308.         strcat (outstr, " ");
  2309.         strcat (outstr, s2);
  2310.     }
  2311.     if (n) {
  2312.         NumToString (n, numstr);
  2313.         p2cstr(numstr);
  2314.         strcat (outstr, " ");
  2315.         strcat (outstr, numstr);
  2316.     }
  2317.     strcat (outstr, "\r");
  2318.  
  2319.     count = strlen (outstr);
  2320.     FSWrite (tlogfile, &count, outstr);
  2321.     }
  2322. }                /* tlog */
  2323. #endif /* COMMENT */
  2324.  
  2325. /****************************************************************************/
  2326. #ifdef TLOG
  2327. #define TBUFL 300
  2328. /*  T L O G  --  Log a record in the transaction file  */
  2329. /*
  2330.  Call with a format and 3 arguments: two strings and a number:
  2331.    f  - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
  2332.    s1,s2 - String arguments 1 and 2.
  2333.    n  - Int, argument 3.
  2334. */
  2335. VOID tlog(f,s1,s2,n) int f; long n; char *s1, *s2; {
  2336.     char s[TBUFL];
  2337.     char *sp = s; int x;
  2338.     
  2339.     if (!tralog) return;        /* If no transaction log, don't */
  2340.     switch (f) {
  2341.         case F000:            /* 0 (special) "s1 n s2"  */
  2342.         if (strlen(s1) + strlen(s2) + 15 > TBUFL)
  2343.           sprintf(sp,"?T-Log string too long\r");
  2344.         else sprintf(sp,"%s %ld %s\r",s1,n,s2);
  2345.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  2346.         break;
  2347.         case F001:            /* 1, " n" */
  2348.         sprintf(sp," %ld\r",n);
  2349.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  2350.         break;
  2351.         case F010:            /* 2, "[s2]" */
  2352.         x = strlen(s2);
  2353.         if (s2[x] == '\n' || s2[x] == '\r') s2[x] = '\0';
  2354.         if (x + 6 > TBUFL)
  2355.           sprintf(sp,"?T-Log string too long\r");
  2356.         else sprintf(sp,"[%s]\r",s2);
  2357.         if (zsout(ZTFILE,"") < 0) tralog = 0;
  2358.         break;
  2359.         case F011:            /* 3, "[s2] n" */
  2360.         x = strlen(s2);
  2361.         if (s2[x] == '\n' || s2[x] == '\r') s2[x] = '\0';
  2362.         if (x + 6 > TBUFL)
  2363.           sprintf(sp,"?T-Log string too long\r");
  2364.         else sprintf(sp,"[%s] %ld\r",s2,n);
  2365.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  2366.         break;
  2367.         case F100:            /* 4, "s1" */
  2368.         if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
  2369.         break;
  2370.         case F101:            /* 5, "s1: n" */
  2371.         if (strlen(s1) + 15 > TBUFL)
  2372.           sprintf(sp,"?T-Log string too long\r");
  2373.         else sprintf(sp,"%s: %ld\r",s1,n);
  2374.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  2375.         break;
  2376.         case F110:            /* 6, "s1 s2" */
  2377.         x = strlen(s2);
  2378.         if (s2[x] == '\n' || s2[x] == '\r') s2[x] = '\0';
  2379.         if (strlen(s1) + x + 4 > TBUFL)
  2380.           sprintf(sp,"?T-Log string too long\r");
  2381.         else sprintf(sp,"%s %s\r",s1,s2);
  2382.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  2383.         break;
  2384.         case F111:            /* 7, "s1 s2: n" */
  2385.         x = strlen(s2);
  2386.         if (s2[x] == '\n' || s2[x] == '\r') s2[x] = '\0';
  2387.         if (strlen(s1) + x + 15 > TBUFL)
  2388.           sprintf(sp,"?T-Log string too long\r");
  2389.         else sprintf(sp,"%s %s: %ld\r",s1,s2,n);
  2390.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  2391.         break;
  2392.     default:
  2393.         sprintf(sp,"\r?Invalid format for tlog() - %ld\r",n);
  2394.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  2395.     }
  2396. }
  2397. #endif /* TLOG */
  2398.  
  2399.  
  2400.  
  2401. short slogfile;
  2402. char slogname[] = "Kermit Session";
  2403.  
  2404. /****************************************************************************/
  2405. /****************************************************************************/
  2406. openslog ()
  2407. {
  2408.     return (openlogfile("Session log name:", slogname, &slogfile, ZSFILE));
  2409. }
  2410.  
  2411.  
  2412. /****************************************************************************/
  2413. /****************************************************************************/
  2414. openlogfile(prompt, name, fdp, n)
  2415. char *prompt, *name;
  2416. short *fdp;
  2417. int n;
  2418. {
  2419.     int err;
  2420.     SFReply sfr;    /* holds file info */
  2421.     Point where;
  2422.     
  2423.     SetPt(&where, 75, 80);
  2424.     SFPutFile (where,
  2425.            c2p_tmp(prompt),
  2426.            c2p_tmp2(name),
  2427.            (DlgHookProcPtr) NILPROC,
  2428.            &sfr);
  2429.     if (!sfr.good)    /* if canceled */
  2430.         return (0);
  2431.  
  2432.     /* p2cstr(&sfr.fName); */
  2433.     
  2434.     err = Create (&sfr.fName, sfr.vRefNum, 'MACA', 'TEXT');
  2435.     if (err != dupFNErr)
  2436.     if (!ioutil (err))
  2437.         return (0);
  2438.  
  2439.     err = FSOpen (&sfr.fName, sfr.vRefNum, fdp); /* open the logfile */
  2440.     if (!ioutil (err))
  2441.     return (0);
  2442.  
  2443.     fp[n].frefnum = *fdp;    /* let normal kermit z- routines know about */
  2444.                     /* the file descriptor */
  2445.     
  2446.     SetFPos (*fdp, fsFromLEOF, 0);    /* set file pointer to eof */
  2447.     
  2448.     return (1);
  2449. }                /* openslog */
  2450.  
  2451.  
  2452.  
  2453. /****************************************************************************/
  2454. /****************************************************************************/
  2455. closeslog ()
  2456. {
  2457.     int err;
  2458.  
  2459.     err = FSClose (slogfile);
  2460.     if (!ioutil (err))
  2461.     return (0);
  2462.     FlushVol (NIL, dfltVol);
  2463. }                /* closeslog */
  2464.  
  2465.  
  2466.  
  2467. /****************************************************************************/
  2468. /* write a maximum of n characters from s to the session log file */
  2469. /* skip all trailing blanks */
  2470. /****************************************************************************/
  2471. slog (s, n)
  2472. char *s;
  2473. int n;
  2474. {
  2475.     long count;
  2476.     char *c;
  2477.  
  2478.     /* skip all non visible characters */
  2479.     for (c = s + n - 1; (*c <= ' ') && (c >= s); c--);
  2480.  
  2481.     /* adjust count and write to file */
  2482.     count = (long) (c - s + 1);
  2483.     FSWrite (slogfile, &count, s);
  2484.  
  2485.     /* write a cr at end of line */
  2486.     count = 1;
  2487.     FSWrite (slogfile, &count, "\r");
  2488. }                /* slog */
  2489.  
  2490. char plogname[] = "Kermit Packets";
  2491.  
  2492. /****************************************************************************/
  2493. /****************************************************************************/
  2494. openplog ()
  2495. {
  2496.     return (openlogfile("Packet log name:",
  2497.             plogname,
  2498.             &fp[ZPFILE].frefnum,
  2499.             ZPFILE));
  2500. }
  2501.  
  2502. /****************************************************************************/
  2503. /****************************************************************************/
  2504. closeplog ()
  2505. {
  2506.     FSClose (fp[ZPFILE].frefnum);
  2507.     FlushVol (NIL, dfltVol);
  2508. }                /* closeplog */
  2509.  
  2510. /****************************************************************************/
  2511. /****************************************************************************/
  2512. opendlog ()
  2513. {
  2514.     /* debugging output goes to the console for the moment */
  2515.     return (zopeno (ZDFILE, "Debugging log file", NULL, NULL));
  2516. }
  2517.  
  2518. /****************************************************************************/
  2519. /****************************************************************************/
  2520. closedlog ()
  2521. {
  2522.     return (zclose(ZDFILE));
  2523. }                /* closedlog */
  2524.  
  2525.  
  2526. /****************************************************************************/
  2527. /****************************************************************************/
  2528. char *
  2529. tilde_expand(dirname) char *dirname; {
  2530.     /* there really isn't any concept of "user's home dir" on the Mac */
  2531.     return("");
  2532. }
  2533.  
  2534. /* Z S T I M E  --  Set creation date for incoming file */
  2535. /*
  2536.  Call with:
  2537.  f  = pointer to name of existing file.
  2538.  yy = pointer to a Kermit file attribute structure in which yy->date.val
  2539.       is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
  2540.  x  = is a function code: 0 means to set the file's creation date as given.
  2541.       1 means compare the given date with the file creation date.
  2542.  Returns:
  2543.  -1 on any kind of error.
  2544.   0 if x is 0 and the file date was set successfully.
  2545.   0 if x is 1 and date from attribute structure <= file creation date.
  2546.   1 if x is 1 and date from attribute structure > file creation date.
  2547. */
  2548.  
  2549. zstime(f,yy,x)
  2550. char *f;
  2551. struct zattr *yy;
  2552. int x;
  2553. {
  2554.     /* $$$ Fill me in */
  2555. }
  2556.  
  2557. #define WINDOW_MAGIC 0xFFF0        /* hopefully unused value */
  2558.  
  2559. /*
  2560.  * mac_fopen
  2561.  * Open a window if special filename.
  2562.  *
  2563.  * We use these fields in the FILE struct:
  2564.  *   _ptr - pointer to cmdw
  2565.  *   _size - character offset of current position
  2566.  *   _flag - holds our magic flag identifier
  2567.  */
  2568. FILE *mac_fopen (char *filename, char *mode)
  2569. {
  2570.     int id;
  2571.     struct cmdw *cmdw;
  2572.     extern struct cmdw *cmdwl;
  2573.     FILE *stream;
  2574.  
  2575.     if (strncmp(filename, "%%%", 3) != 0) /* if normal open */
  2576.     return(fopen(filename, mode));
  2577.  
  2578.     /*
  2579.      * Find the window
  2580.      */
  2581.     id = atoi(&filename[3]);
  2582.     for (cmdw = cmdwl; cmdw; cmdw = cmdw->next)
  2583.     if (id == cmdw->id)
  2584.         break;
  2585.     if (!cmdw)
  2586.     return NULL;
  2587.  
  2588.     /*
  2589.      * Allocate and preset FILE struct
  2590.      */
  2591.     stream = (FILE *)malloc(sizeof(FILE));
  2592.     if (!stream) {
  2593.     printfalert("mac_fopen: no memory for FILE");
  2594.     return NULL;
  2595.     }
  2596. #ifdef MPW
  2597.     stream->_flag = WINDOW_MAGIC;
  2598.     stream->_size = 0;
  2599.     stream->_ptr = (unsigned char *)cmdw;
  2600. #else /* !MPW */
  2601.  
  2602. YOU MUST FIGURE OUT HOW TO DO THE SAME THING FOR NON-MPW ENVIRONMENTS!!!
  2603.  
  2604. #endif /* MPW */
  2605.     cmdw->flags |= CMDWF_FOPEN;
  2606.  
  2607.     return(stream);
  2608. }
  2609.  
  2610.  
  2611. /*
  2612.  * mac_fclose
  2613.  */
  2614. int mac_fclose (FILE *stream)
  2615. {
  2616.     struct cmdw *cmdw;
  2617.  
  2618.     if (stream->_flag != WINDOW_MAGIC)
  2619.     return(fclose(stream));
  2620.  
  2621.     cmdw = (struct cmdw *)stream->_ptr;
  2622.     cmdw->flags &= ~CMDWF_FOPEN;    /* clear file open */
  2623.  
  2624.     free(stream);
  2625.     return 0;
  2626. }
  2627.  
  2628.  
  2629. /*
  2630.  * mac_rewind
  2631.  */
  2632. void mac_rewind (FILE *stream)
  2633. {
  2634.     if (stream->_flag != WINDOW_MAGIC) {
  2635.     rewind(stream);
  2636.     return;
  2637.     }
  2638.  
  2639.     stream->_size = 0;
  2640. }
  2641.  
  2642.  
  2643. /*
  2644.  * mac_fgets
  2645.  */
  2646. char *mac_fgets (char *s, int n, FILE *stream)
  2647. {
  2648.     struct cmdw *cmdw;
  2649.     CharsHandle h;
  2650.     long len;
  2651.     char *cp;
  2652.     unsigned short fpos;
  2653.     int nstored;
  2654.  
  2655.     if (stream->_flag != WINDOW_MAGIC)
  2656.     return (fgets(s, n, stream));
  2657.  
  2658.     cmdw = (struct cmdw *)stream->_ptr;
  2659.     h = TEGetText(cmdw->teh);
  2660.     len = (*cmdw->teh)->teLength;
  2661.     cp = (char *)*h;            /* pointer to chars in window */
  2662.     fpos = stream->_size;        /* file position */
  2663.     
  2664.     if (fpos >= len)            /* if already eof */
  2665.     return NULL;
  2666.  
  2667.     /*
  2668.      * Transfer characters until n-1 chars have been transfered, 
  2669.      * a newline has been transferred, or we have reached the
  2670.      * end of the window.  Terminate the buffer with a null.
  2671.      */
  2672.     nstored = 0;
  2673.     while (fpos < len) {
  2674.     if (nstored >= n-1)
  2675.         break;
  2676.     s[nstored] = cp[fpos++];
  2677.     if (s[nstored++] == '\n')
  2678.         break;
  2679.     }
  2680.     s[nstored++] = '\0';        /* terminate string */
  2681.     stream->_size = fpos;        /* remember position */
  2682.  
  2683.     return s;
  2684. }
  2685.  
  2686.  
  2687. /*
  2688.  * mac_feof
  2689.  */
  2690. int mac_feof (FILE *stream)
  2691. {
  2692.     struct cmdw *cmdw;
  2693.     long len;
  2694.  
  2695.     if (stream->_flag != WINDOW_MAGIC)
  2696.     return(feof(stream));
  2697.  
  2698.     cmdw = (struct cmdw *)stream->_ptr;
  2699.     len = (*cmdw->teh)->teLength;
  2700.  
  2701.     if (stream->_size >= len)
  2702.     return TRUE;
  2703.     else
  2704.     return FALSE;
  2705. }
  2706.  
  2707.  
  2708. /*
  2709.  * Junk so Emacs will set local variables to be compatible with Mac/MPW.
  2710.  * Should be at end of file.
  2711.  * This module uses 8 char tabs
  2712.  * 
  2713.  * Local Variables:
  2714.  * tab-width: 8
  2715.  * End:
  2716.  */
  2717.